题目大意:有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;
}