bzoj4380: [POI2015]Myjnie【区间dp】

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/cdsszjj/article/details/80345303

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],ci

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

解题思路:

由贪心可知,最后的p[i]肯定是某个c[i]。
首先将 c 离散化,考虑区间 DP,设 f(i,j,k) 为区间 [i,j] 最小值为 k 时的最大收益(只考虑i<=a<=b<=j的人)。
转移时枚举最小值所在位置 x,那么可以用f(i,x–1,≥k)+f(x+1,j,≥k)+cnt[x][k]*k 来更新 f(i,j,k),cnt[x][k]为考虑的人中经过x且c[i]≥k的人数,他们肯定都会选k。
时间复杂度 O(n^3m),要输出方案则记录决策点即可。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int getint()
{
    int i=0,f=1;char c;
    for(c=getchar();(c!='-')&&(c<'0'||c>'9');c=getchar());
    if(c=='-')c=getchar(),f=-1;
    for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
    return i*f;
}
const int N=55,M=4005;
int n,m,mx,a[M],b[M],c[M],val[M],ans[N],f[N][N][M],cnt[N][M],g[N][N][M],p[N][N][M];
void get_ans(int l,int r,int k)
{
    if(l>r)return;
    int i=p[l][r][k],j=g[l][r][k];
    ans[i]=val[j];
    get_ans(l,i-1,j),get_ans(i+1,r,j);
}
int main()
{
    //freopen("lx.in","r",stdin);
    n=getint(),m=getint();
    for(int i=1;i<=m;i++)a[i]=getint(),b[i]=getint(),c[i]=val[i]=getint();
    sort(val+1,val+m+1),mx=unique(val+1,val+m+1)-val-1;
    for(int i=1;i<=m;i++)c[i]=lower_bound(val+1,val+mx+1,c[i])-val;
    for(int l=n;l;l--)for(int r=l;r<=n;r++)
    {
        for(int i=l;i<=r;i++)for(int k=1;k<=mx;k++)cnt[i][k]=0;
        for(int i=1;i<=m;i++)if(l<=a[i]&&b[i]<=r)
            for(int j=a[i];j<=b[i];j++)cnt[j][c[i]]++;
        for(int i=l;i<=r;i++)for(int k=mx;k;k--)cnt[i][k]+=cnt[i][k+1];
        for(int k=mx;k;k--)
        {
            p[l][r][k]=l,g[l][r][k]=k;
            for(int i=l;i<=r;i++)
            {
                int tmp=f[l][i-1][k]+f[i+1][r][k]+cnt[i][k]*val[k];
                if(tmp>f[l][r][k])f[l][r][k]=tmp,p[l][r][k]=i;
            }
            if(f[l][r][k+1]>f[l][r][k])f[l][r][k]=f[l][r][k+1],g[l][r][k]=g[l][r][k+1],p[l][r][k]=p[l][r][k+1];
        }
    }
    cout<<f[1][n][1]<<'\n';
    get_ans(1,n,1);
    for(int i=1;i<=n;i++)cout<<ans[i]<<' ';
    return 0;
}
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页