题目来源于:洛谷
题目本质:动态规划及优化,单调队列
题目思路:
设 fi,k,op 表示对于前 i 个位置,强制在 i+1 分钟初踱步,总共踱步 k 次,且第 i 分钟在屋内(op=0)或屋外(op=1)的最大答案。
显然我们有以下转移方程:
fi,k,op=j=k−1maxi−1fj,k−1,1−op+si,op−sj,op+[i−j≤T]P
移项可得:
fi,k,op−si,op=j=k−1maxi−1fj,k−1,1−op−sj,op+[i−j≤T]P
滚动数组滚掉一维:
gi,op−si,op=j=k−1maxi−1fj,1−op−sj,op+[i−j≤T]P
完整代码如下:
#include<bits/stdc++.h>
#define int long long
#define N 200010
using namespace std;
int id,T,n,m,t,p;
int f[N][2],s[N][2],g[N][2],q[N];
int get(int x,int y){return f[x][y^1]-s[x][y];}
void work(int pos,int op){
int now=-1e18;
int l=1,r=1;
q[1]=pos-1;
for(int i=pos;i<=n;i++){
if(i-t-1>=pos-1){
now=max(now,get(i-t-1,op));
}
while(l<=r&&q[l]<i-t){
l++;
}
g[i][op]=max(now,get(q[l],op)+p)+s[i][op];
while(l<=r&&get(i,op)>=get(q[r],op)){
r--;
}
q[++r]=i;
}
}
signed main(){
cin>>id>>T;
while(T--){
cin>>n>>m>>t>>p;
for(int i=1;i<=n;i++){
cin>>s[i][0]>>s[i][1];
s[i][0]+=s[i-1][0];
s[i][1]+=s[i-1][1];
f[i][0]=s[i][0];
f[i][1]=s[i][1];
}
int ans=max(s[n][0],s[n][1]);
for(int i=1;i<n;i++) ans=max(ans,max(f[i][0]+s[n][1]-s[i][1],f[i][1]+s[n][0]-s[i][0]));//一次踱步
for(int pos=2;pos<=m;pos++){
work(pos,0),work(pos,1);
for(int i=pos;i<n;i++){
f[i][0]=g[i][0];
f[i][1]=g[i][1];
ans=max(ans,max(f[i][0]+s[n][1]-s[i][1],f[i][1]+s[n][0]-s[i][0]));
}
}
cout<<ans<<endl;
}
return 0;
}