这题的转移很明显。
用dp[i][j] 表示到达i层j位置时的最大得分
sum[i][j] 表示第i层前j个数的和
dp[i][j] = max(max(dp[i - 1][j + k] + sum[i-1][j +k-1] - sum[i - 1][j - 1] + score[i][j]), max(dp[i - 1][j - k] - sum[i-1][j -k] + sum[i - 1][j] + score[i][j]))
因为只能移动t步,则就是在t长的窗口中的最小值
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<cstdlib> using namespace std; const int inf=0x3f3f3f3f; inline int read() { int x; scanf("%d",&x); return x; } int n,m,x,t; int sco[105][10005],sum[105][10005],f[105][10005]; int q[10005],id[10005],head,tail; void work() { m=read();x=read();t=read(); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) sco[i][j]=read(),sum[i][j]=sum[i][j-1]+sco[i][j]; for (int i=1;i<=m;i++) if (i!=x) f[1][i]=-inf;else f[1][i]=sco[1][i]; for (int i=2;i<=n+1;i++) { memset(q,0,sizeof(q)); memset(id,0,sizeof(id)); head=1;tail=1; q[1]=f[i-1][1]-sum[i-1][1]; id[1]=1;//注意初始化,不要忘了id【1】之类的 for (int j=1;j<=m;j++) { f[i][j]=-inf; while (head<=tail && id[head]<j-t) head++; f[i][j]=max(f[i][j],q[head]+sco[i][j]+sum[i-1][j]); while (head<=tail && q[tail]<=f[i-1][j+1]-sum[i-1][j+1]) tail--; q[++tail]=f[i-1][j+1]-sum[i-1][j+1]; id[tail]=j+1; } /***********************************************/ memset(q,0,sizeof(q)); memset(id,0,sizeof(id)); head=1;tail=1; q[1]=f[i-1][m]+sum[i-1][m-1]; id[1]=m; for (int j=m;j>=1;j--) { while (head<=tail && id[head]>j+t) head++; f[i][j]=max(f[i][j],q[head]+sco[i][j]-sum[i-1][j-1]); while (head<=tail && q[tail]<=f[i-1][j-1]+sum[i-1][j-2]) tail--; q[++tail]=f[i-1][j-1]+sum[i-1][j-2]; id[tail]=j-1; } } int ans=-inf; for (int i=1;i<=m;i++) ans=max(ans,f[n+1][i]); printf("%d\n",ans); } void clear() { memset(sum,0,sizeof(sum)); memset(sco,0,sizeof(sco)); memset(f,0,sizeof(f)); } int main() { while (scanf("%d",&n)!=EOF) { clear(); work(); } return 0; }