BZOJ4380: [POI2015]Myjnie

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。
若有多组最优解,输出任意一组。

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
 
将所有c[i]离散,设f[l][r][j]表示[l,r]区间内,最小值>=j的收益。
设g[x][j]表示所有[l,r]中c[i]>=j的区间个数,即每个人的贡献,然后序列DP即可。
时间复杂度为O(N^3*M)
#include<cstdio>
#include<cctype>
#include<queue>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i;i=next[i])
using namespace std;
const int BufferSize=1<<16;
char buffer[BufferSize],*head,*tail;
inline char Getchar() {
	if(head==tail) {
		int l=fread(buffer,1,BufferSize,stdin);
		tail=(head=buffer)+l;
	}
	return *head++;
}
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}
const int maxn=55;
const int maxm=4005;
int n,m,B[maxn],s[maxm],t[maxm],A[maxm],tmp[maxm];
int f[maxn][maxn][maxm],p[maxn][maxn][maxm],g[maxn][maxm];
void print(int l,int r,int j) {
	if(l>r) return;
	int x=p[l][r][j];
	if(!x) print(l,r,j+1);
	else print(l,x-1,j),B[x]=tmp[j],print(x+1,r,j);
}
int main() {
	n=read();m=read();
	rep(i,1,m) s[i]=read(),t[i]=read(),A[i]=tmp[i]=read();
	sort(tmp+1,tmp+m+1);
	rep(i,1,m) A[i]=lower_bound(tmp+1,tmp+m+1,A[i])-tmp;
	dwn(l,n,1) rep(r,l,n) {
		rep(i,l,r) rep(j,1,m) g[i][j]=0;
		rep(j,1,m) if(l<=s[j]&&t[j]<=r) g[s[j]][A[j]]++,g[t[j]+1][A[j]]--;
		rep(i,l,r) rep(j,1,m) g[i][j]+=g[i-1][j];
		rep(i,l,r) dwn(j,m,2) g[i][j-1]+=g[i][j];
		dwn(j,m,1) {
			int& ans=f[l][r][j];
			rep(x,l,r) {
				int res=f[l][x-1][j]+f[x+1][r][j]+tmp[j]*g[x][j];
				if(res>=ans) p[l][r][j]=x,ans=res;
			}
			if(f[l][r][j+1]>ans) {
				ans=f[l][r][j+1];
				p[l][r][j]=0;
			}
		}
	}
	printf("%d
",f[1][n][1]);
	print(1,n,1);
	rep(i,1,n) printf("%d%c",B[i],i==n?'
':' ');
	return 0;
}

  

原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/5413982.html