单调队列优化DP
//状态转移方程:f[i][j]=min(f[i-k][j-1]+(s[i]-s[i-p])*g[j]) #include <iostream> #include <cstdio> #include <cstring> #define LL long long using namespace std; const LL inf=0x3f3f3f3f3f3f3f3f; LL x[10000+10],s[10000+10],q[10000+10]; LL g[200+10]; LL f[2][10000+10]; int n,k,a,b; int front,rear; int main() { while(~scanf("%d%d%d%d",&n,&k,&a,&b)) { int i,j; LL ave=0; LL minv=inf; int loc,amount; s[0]=0; for(i=1;i<=n;i++) { scanf("%lld",&x[i]); ave+=x[i]; } ave/=n; for(i=1;i<=n;i++) { x[i]=(x[i]-ave)*(x[i]-ave); s[i]=s[i-1]+x[i]; } for(i=1;i<=k;i++) scanf("%lld",&g[i]); memset(f,inf,sizeof(f));//memset也很费时间,因为此处,无限TLE,所以将f[210][N]改为f[2][N],又省空间又省时间 f[0][0]=0; int p; for(i=1,p=1;i<=k;i++,p=!p) { front=rear=0; memset(f[p],inf,sizeof(f[p])); for(j=i*a;j<=i*b&&j<=n;j++) { while(front<rear&&((f[!p][q[rear-1]]-s[q[rear-1]]*g[i])>=(f[!p][j-a]-s[j-a]*g[i]))) rear--; //注意是小于等于,由于疏忽了这句“output the smaller T.”,导致无限WA q[rear++]=j-a; while(front<rear&&q[front]<(j-b)) front++; f[p][j]=f[!p][q[front]]+(s[j]-s[q[front]])*g[i]; } if(f[p][n]<minv) { minv=f[p][n]; loc=i; amount=n-q[front]; } } if(minv<inf) printf("%lld %d %d\n",minv,loc,amount); else printf("No solution.\n"); } return 0; }