zoj 3399

来源:互联网 发布:windows 登陆服务器 编辑:程序博客网 时间:2024/05/22 01:30

单调队列优化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 longusing 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;}


原创粉丝点击