BZOJ4380 POI2015 Myjnie

来源:互联网 发布:steam mac 存档 编辑:程序博客网 时间:2024/06/06 14:01

Description

有n家洗车店从左往右排成一排,每家店都有一个正整数价格p[i]。

有m个人要来消费,第i个人会驶过第a[i]个开始一直到第b[i]个洗车店,且会选择这些店中最便宜的一个进行一次消费。但是如果这个最便宜的价格大于c[i],那么这个人就不洗车了。

请给每家店指定一个价格,使得所有人花的钱的总和最大。

Input

第一行包含两个正整数n,m(1n501m4000)

接下来m行,每行包含三个正整数a[i],b[i],c[i] (1a[i]b[i]n,1c[i]5×105)

Output

第一行输出一个正整数,即消费总额的最大值。

第二行输出n个正整数,依次表示每家洗车店的价格p[i],要求1<=p[i]<=500000。

若有多组最优解,输出任意一组。

Sample Input

7 5
1 4 7
3 7 13
5 6 20
6 7 1
1 2 5

Sample Output

43
5 5 13 13 20 20 13


Solution:

玄学三维dp,膜Claris大犇。

还是提醒自己先不要考虑方案输出。事实证明先考虑方案就会想到贪心爆搜等奇怪的思路上。

对于当前这个询问区间,它的贡献是vali={min[L,R]0min[L,R]Limitimin[L,R]>Limiti

思考对象为区间的话感觉没有什么思路,我们考虑每个洗车店对答案的贡献:在什么情况下,哪些车辆会在当前的洗车店消费?

  • 在某段区域内,当前这个洗车店为最小值,就会导致在该区域内并且经过该洗车店的车辆在此处进行消费。

于是我们按照上述内容进行dp就好了,定义dp[L][R][k]表示在区间[L,R]内,该区间的最小值最小为k时,全部路程在[L,R]内的汽车的最优总贡献。之后枚举哪一家洗车店的价格定为k,统计区间经过当前洗车店,并且Limitik的车辆总数,记为h[i][k]。于是得到转移方程式(显然这个k我们需要离散,对应的数组在我的代码中记作res[k]):

dp[L][R][k]=max{dp[L][p1][k]+dp[p+1][R][k]+res[k]×h[p][k]dp[L][R][w]p[L,R]w[k,m]

这样最优解就得到了,接下来打印方案的话,我们存储从哪个洗车店转移此时洗车店的最优定价(因为我们关于dp的定义没有确定当前枚举的消费值就是最优解……)。类似二叉树一样不断将区间劈成两部分递归处理即可。对应到我的代码中分别为f数组和v数组。

最后总复杂度为O(n3m)(果然数据范围小没什么好事情……)。

就当做是补充Claris大犇短小的题解吧2333

#include <cstdio>#include <cstring>#include <algorithm>#define N 55#define M 4005template <class temp>inline bool check_max(temp &a,temp b){    if(a>=b)return false;    a=b;return true;}int dp[N][N][M],v[N][N][M],f[N][N][M],h[N][M];int a[M],b[M],c[M],res[M];int ans[M];void dfs(int l,int r,int col){    if(l>r)return;    int mid=f[l][r][col];    ans[mid]=v[l][r][col];    col=v[l][r][col];    dfs(l,mid-1,col),dfs(mid+1,r,col);}int main(){    int n,m;    scanf("%d %d",&n,&m);    for(int i=1;i<=m;i++){        scanf("%d %d %d",&a[i],&b[i],&c[i]);        res[i]=c[i];    }    std::sort(res+1,res+m+1);    for(int i=1;i<=m;i++)        c[i]=std::lower_bound(res+1,res+m+1,c[i])-res;    for(int t=1;t<=n;t++)        for(int l=1;l+t-1<=n;l++){            int r=l+t-1;            for(int i=l-1;i<=r;i++)                for(int j=1;j<=m;j++)h[i][j]=0;            for(int i=1;i<=m;i++)                if(l<=a[i]&&b[i]<=r)                    h[a[i]][c[i]]++,h[b[i]+1][c[i]]--;            for(int j=1;j<=m;j++)                for(int i=l;i<=r;i++)h[i][j]+=h[i-1][j];            for(int i=l;i<=r;i++)                for(int j=m;j>=1;j--)h[i][j]+=h[i][j+1];            for(int k=m;k>=1;k--){                f[l][r][k]=l,v[l][r][k]=k;                for(int i=l;i<=r;i++)                    if(check_max(dp[l][r][k],dp[l][i-1][k]+dp[i+1][r][k]+res[k]*h[i][k]))                        f[l][r][k]=i,v[l][r][k]=k;            }            for(int k=m-1;k>=1;k--)                if(check_max(dp[l][r][k],dp[l][r][k+1]))                    f[l][r][k]=f[l][r][k+1],v[l][r][k]=v[l][r][k+1];        }    printf("%d\n",dp[1][n][1]);    dfs(1,n,1);    printf("%d",(!ans[1])?res[m]:res[ans[1]]);    for(int i=2;i<=n;i++)        printf(" %d",(!ans[i])?res[m]:res[ans[i]]);    putchar('\n');}
0 0
原创粉丝点击