BZOJ4380: [POI2015]Myjnie

来源:互联网 发布:python pack_into 编辑:程序博客网 时间:2024/06/06 05:06

因为每个人不洗车的条件是最小价格大于c[i],所以易知最后每家店的价格都是c[i]一定有一种方案使得所有人花的钱总和最大
那么就和c[i]的具体数值无关,先把它离散化
然后因为一个人决策的标准和区间的最小值有关,将c[i]引入状态定义,
定义f[i][j][c]代表ij的最小值为c,这个区间包含的人花的钱最多是多少,枚举左端点DP

于是枚举ij中的某个点k的值为c进行转移,尝试写转移方程时,发现需要知道kij中的多少个人包含,于是还要维护一个h[k][c]表示对于当前DP区间,经过k且价格要求大于等于c的有多少个人
那么写出方程

f[i][j][c]=max(max(f[i][k1][c2],c2>=c)+max(f[i][k+1][c3],c3>=c)+ch[k][c])

发现仍然不太好转移,所以还要维护一个g[i][j][c]表示max(f[i][j][k],k>=c)
维护了这三个后就可以DP求解了

答案就是g[1][n][1],然后要求输出方案,可以在转移的时候记录每个f是哪个位置取了c值,搜一下就好了

code:

#include<set>#include<map>#include<deque>#include<queue>#include<stack>#include<cmath>#include<ctime>#include<bitset>#include<string>#include<vector>#include<cstdio>#include<cstdlib>#include<cstring>#include<climits>#include<complex>#include<iostream>#include<algorithm>#define ll long longusing namespace std;inline void up(int &x,const int &y){if(x<y)x=y;}const int maxn = 55;const int maxm = 4100;const int maxc = 510000;struct node{    int a,b,c;}a[maxm];inline bool cmp(node x,node y){return x.b==y.b?x.a<y.a:x.b<y.b;}int f[maxn][maxn][maxm],g[maxn][maxn][maxm],h[maxn][maxm];int p[maxn][maxn][maxm],val[maxn];int C[maxm],lsh[maxc],LSH[maxm],K;int n,m;void pre(){    sort(a+1,a+m+1,cmp);    sort(C+1,C+m+1); K=0;    for(int i=1;i<=m;i++)        if(C[i]!=C[i-1]) LSH[++K]=C[i],lsh[C[i]]=K;    for(int i=1;i<=m;i++) a[i].c=lsh[a[i].c];}void search(int l,int r,int k){    if(l>r) return ;    if(!g[l][r][k])    {        for(int i=l;i<=r;i++) val[i]=LSH[k];        return ;    }    for(int i=k;i<=K;i++) if(g[l][r][k]==f[l][r][i])    {        const int pos=p[l][r][i];        val[pos]=LSH[i];        search(l,pos-1,i); search(pos+1,r,i);        break;    }}int main(){    scanf("%d%d",&n,&m);    for(int i=1;i<=m;i++)         scanf("%d%d%d",&a[i].a,&a[i].b,&a[i].c),C[i]=a[i].c;    pre();    for(int l=n;l>=1;l--) for(int r=l;r<=n;r++)    {        for(int i=l;i<=r;i++) for(int j=1;j<=K;j++) h[i][j]=0;        for(int i=1;i<=m&&a[i].b<=r;i++)        {            if(a[i].a<l) continue;            for(int j=a[i].a;j<=a[i].b;j++) h[j][a[i].c]++;        }        for(int i=l;i<=r;i++) for(int j=K-1;j>=1;j--) h[i][j]+=h[i][j+1];        for(int i=l;i<=r;i++)        {            for(int j=K;j>=1;j--)            {                int tmp=g[l][i-1][j]+g[i+1][r][j]+h[i][j]*LSH[j];                if(f[l][r][j]<tmp) f[l][r][j]=tmp,p[l][r][j]=i;                g[l][r][j]=g[l][r][j+1]>f[l][r][j]?g[l][r][j+1]:f[l][r][j];            }        }    }    printf("%d\n",g[1][n][1]);    search(1,n,1);    for(int i=1;i<=n;i++) printf("%d ",val[i]);    return 0;}
0 0
原创粉丝点击