ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

Description

有n家洗车店从左往右排成一排,每家店都有一个正整数价格p[i]。
有m个人要来消费,第i个人会驶过第a[i]个开始一直到第b[i]个洗车店,且会选择这些店中最便宜的一个进行一次消费。但是如果这个最便宜的价格大于c[i],那么这个人就不洗车了。
请给每家店指定一个价格,使得所有人花的钱的总和最大。

Input

第一行包含两个正整数n,m(1<=n<=50,1<=m<=4000)。
接下来m行,每行包含三个正整数a[i],b[i],c[i](1<=a[i]<=b[i]<=n,1<=c[i]<=500000)

Output

第一行输出一个正整数,即消费总额的最大值。
第二行输出n个正整数,依次表示每家洗车店的价格p[i],要求1<=p[i]<=500000。
若有多组最优解,输出任意一组。

用dp确定笛卡尔树的形态,f[l][r][v]表示区间[l,r]的最小值为v时,区间内的最大收益,转移时枚举最小值的位置用子区间更新,时间复杂度$O(n^3m)$。
#include<bits/stdc++.h>
int n,m,ls[4111],rs[4111],v0[4111],v1[4111],vs[4111],v2[4111];
int f[53][53][4011],g[53][53][4011],fw[53][53][4011];
inline bool in(int a,int l,int r){return l<=a&&a<=r;}
inline bool maxs(int&a,int b){return a<b?a=b,1:0;}
inline int max(int a,int b){return a>b?a:b;}
void pr(int l,int r,int h){
    if(l>r)return;
    int h1=h;
    for(;f[l][r][h1]!=g[l][r][h];--h1);
    int p=fw[l][r][h1];
    if(!p)p=l;
    pr(l,p-1,h1);
    printf("%d ",vs[h1]);
    pr(p+1,r,h1);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;++i)scanf("%d%d%d",ls+i,rs+i,v0+i),vs[i]=v0[i];
    std::sort(vs+1,vs+m+1,std::greater<int>());
    for(int i=1;i<=m;++i)v1[i]=std::lower_bound(vs+1,vs+m+1,v0[i],std::greater<int>())-vs;
    for(int l=n;l;--l){
        for(int r=l;r<=n;++r){
            int*F=f[l][r],*G=g[l][r],*FW=fw[l][r];
            for(int p=l;p<=r;++p){
                for(int h=1;h<=m;++h)v2[h]=0;
                for(int h=1;h<=m;++h)if(in(ls[h],l,p)&&in(rs[h],p,r))++v2[v1[h]];
                for(int h=2;h<=m;++h)v2[h]+=v2[h-1];
                int*GL=g[l][p-1],*GR=g[p+1][r];
                for(int h=1;h<=m;++h)if(maxs(F[h],GL[h]+GR[h]+v2[h]*vs[h]))FW[h]=p;
            }
            for(int h=1;h<=m;++h)G[h]=max(G[h-1],F[h]);
        }
    }
    printf("%d\n",g[1][n][m]);
    pr(1,n,m);
    return 0;
}

 

posted on 2017-09-15 15:40  nul  阅读(413)  评论(0编辑  收藏  举报