BZOJ4897: [Thu Summer Camp2016]成绩单 DP

来源:互联网 发布:淘宝上男装剪标折扣店 编辑:程序博客网 时间:2024/06/08 16:08

题意:http://www.lydsy.com/JudgeOnline/problem.php?id=4897
首先每一次取的代价是相互独立的,其次考虑对于值域相同的一段,拿走它的代价是一定的,所以凡是值域相同的一段都可以同等看待。那么可以设f[i][j][k][l]表示i到j,剩下的数值域是k到l的最小代价,注意不一定要把所有k到l内的数都剩下。转移时对于一个区间,枚举一个要扩张到的端点,把中间隔着的数以最优方案全部取完即可。对于每个状态,把这些剩下的数一次性取完的代价是已知的,以此来更新把这个区间全部取完的最优值。

#include<cstdio>#include<cstring>#include<algorithm>#define gm 52using namespace std;int n,a,b,w[gm],d[gm];int f[gm][gm],g[gm][gm][gm][gm];inline void cmin(int &a,int b){b<a?a=b:0;}int main(){    memset(f,0x3c,sizeof f);memset(g,0x3c,sizeof g);    scanf("%d%d%d",&n,&a,&b);    for(int i=1;i<=n;++i){scanf("%d",w+i);d[i]=w[i];}    sort(d+1,d+n+1); int tot=unique(d+1,d+n+1)-d-1;    for(int i=1;i<=n;++i) {w[i]=lower_bound(d+1,d+tot+1,w[i])-d;f[i][i]=a;g[i][i][w[i]][w[i]]=f[i][i-1]=0;memset(g[i][i-1],0,sizeof g[i][i-1]);}    f[n+1][n]=0;    for(int L=2;L<=n;++L)    for(int l=1,r=L;r<=n;++l,++r)    {        for(int m=l-1;m<r;++m)        for(int i=1;i<=tot;++i)        for(int j=i;j<=tot;++j)        cmin(g[l][r][min(i,w[r])][max(j,w[r])],g[l][m][i][j]+f[m+1][r-1]);        for(int m=l;m<=r;++m)        for(int i=1;i<=tot;++i)        for(int j=i;j<=tot;++j)        cmin(f[l][r],g[l][m][i][j]+a+b*(d[j]-d[i])*(d[j]-d[i])+f[m+1][r]);    }    printf("%d\n",f[1][n]);    return 0;}
原创粉丝点击