4380: [POI2015]Myjnie

题目链接

题目大意:有n家洗车店,每家店都有一个正整数价格p[i]。
有m个人要来消费,第i个人会选择a[i]~b[i]这些店中最便宜的一个进行一次消费。但是如果这个最便宜的价格大于c[i],那么这个人就不洗车了。请给每家店指定一个价格,使得所有人花的钱的总和最大。

题解:比较烦的区间dp……
Orz 题解

我的收获:常规操作……

#include <bits/stdc++.h>
using namespace std;

#define Rep(x,n,m) for(int x=n;x<=m;x++)
#define Gep(x,n,m) for(int x=n;x>=m;x--)

const int INF=1e8;
const int N=55;
const int MX=4005;

int n,m;
int a[MX],b[MX],c[MX],z[MX];
int cnt[N][MX],C[MX],price[N];
int f[N][N][MX],from[N][N][MX],last[N][N][MX];

void Get(int l,int r,int p)
{
    if(l>r) return;
    int fr=from[l][r][p],la=last[l][r][p];
    price[fr]=C[la];
    Get(l,fr-1,la);Get(fr+1,r,la);
}

void Dp()
{
    Rep(i,1,n) Rep(j,i,n) Rep(k,1,m) f[i][j][k]=-INF;
    Rep(L,1,n) for(int l=1,r=l+L-1;r<=n;l++,r++)
    {
        Rep(k,l,r) Rep(i,1,m) cnt[k][i]=0;
        Rep(i,1,m) if(a[i]>=l&&b[i]<=r) Rep(k,a[i],b[i]) cnt[k][c[i]]++;
        Rep(k,l,r) Gep(i,m,1) cnt[k][i]+=cnt[k][i+1];
        Rep(k,l,r) Rep(i,1,m){
            if(f[l][k-1][i]+f[k+1][r][i]+C[i]*cnt[k][i]>f[l][r][i])
            f[l][r][i]=f[l][k-1][i]+f[k+1][r][i]+C[i]*cnt[k][i],
            from[l][r][i]=k,last[l][r][i]=i;
        }
        Gep(i,m,1) if(f[l][r][i]<f[l][r][i+1])
        f[l][r][i]=f[l][r][i+1],from[l][r][i]=from[l][r][i+1],last[l][r][i]=last[l][r][i+1];
    }
}

void work()
{
    Dp();
    printf("%d\n",f[1][n][1]);
    Get(1,n,1);
    Rep(i,1,n) printf("%d ",price[i]);
    putchar('\n');
}

void init()
{
    scanf("%d%d",&n,&m);
    Rep(i,1,m) scanf("%d%d%d",&a[i],&b[i],&c[i]),z[i]=c[i];
    sort(z+1,z+1+m);int M=unique(z+1,z+1+m)-z-1;
    Rep(i,1,m){int x=lower_bound(z+1,z+1+M,c[i])-z;C[x]=c[i],c[i]=x;}
}

int main()
{
    init();
    work();
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值