http://acm.hdu.edu.cn/showproblem.php?pid=4374
題意:很簡單,不廢話了- -
在這道題中單調隊列的作用:線上性時間內維護定長區間的最值。單調隊列沒學過的話去學一下這題吧
轉移的時候dp[i][k]->dp[i+1][j],k與j的差距不超過T,分兩種情況轉移,k在j的左邊和右邊,所以維護T長度的最值,雙向掃一遍就OK了
(從右邊掃過來)
k j j k
<--------T-------> <--------T------->
dp[i+j][j]=max(dp[i][k]+sum[i+1][j]-sum[i][k-1]) sum[i][j]為第i行的前j項和 所以可以維護一個dp[i][k]-sum[i][k-1]的最大值,每到一個位置j,在區間長度合法的情況下用維護的最大值mx+sum[i+1][j]來更新dp[i+1][j]
從右往左再來一遍即可
具體邊界必須要想清楚
#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn = 10010;const int inf = ~0u>>2;struct DQ{ int f,r; int c[maxn]; int v[maxn]; void init(){f=0;r=-1;} inline void check(int cc){ while(f<=r && c[f]<cc) f++; } inline void push(int cc,int vv) { while(f<=r && v[r]<=vv) r--; c[++r]=cc; v[r]=vv; } void print() { printf("f==%d r==%d\n",f,r); for(int i=f;i<=r;i++) { printf("(%d,%d)",c[i],v[i]); } puts(""); }}q,ql,qr;int dp[maxn],tmp[maxn];int sum[maxn];int main(){ int n,m,x,t; //printf("%d\n",inf); while(scanf("%d%d%d%d",&n,&m,&x,&t)!=EOF) { fill(dp,dp+m+1,-inf); dp[x]=0; for(int i=1;i<=n;i++) { sum[0]=0; q.init(); memcpy(tmp,dp,sizeof(dp)); fill(dp,dp+m+1,-inf); for(int j=1;j<=m;j++) { scanf("%d",&sum[j]); q.push(j,tmp[j]-sum[j-1]); sum[j]+=sum[j-1]; int cc=j-t; if(cc>=1) q.check(cc); dp[j]=max(dp[j],q.v[q.f]+sum[j]); } q.init(); for(int j=m;j>=1;j--) { q.push(m-j+1,tmp[j]+sum[j]); int cc=m-j+1-t; if(cc>=1) q.check(cc); dp[j]=max(dp[j],q.v[q.f]-sum[j-1]); } } int ans=-inf; for(int i=1;i<=m;i++) { if(dp[i]>ans) ans=dp[i]; } printf("%d\n",ans); } return 0;}