luogu P3592 [POI2015]MYJ

题目链接

luogu P3592 [POI2015]MYJ

题解

区间dp
设f[l][r][k]表示区间l到r内最小值>=k的最大收益
枚举为k的位置p,那么包含p的区间答案全部是k
设h[i][j]表示 当前区间穿过i,且c>=j的区间数量,对i的。
然后我们可以做差分,扫一遍,递推出来
\(f[l][r][k]=max(max(f[l][p][k]+f[p+1][r][k]+h[p][k]×k,p∈[l,r]),f[l][r][k+1])\)
对于c离散化
输出方案吼啊

代码

/* 
区间dp
设f[l][r][k]表示区间l到r内最小值>=k的最大收益
枚举为k的位置p,那么包含p的区间答案全部是k 
设h[i][j]表示 当前区间穿过i,且c>=j的区间数量,对i的。
然后我们可以做差分,扫一遍,递推出来 
f[l][r][k]=max(max(f[l][p][k]+f[p+1][r][k]+h[p][k]×k,p∈[l,r]),f[l][r][k+1])
对于c离散化 
*/ 
#include<cstdio> 
#include<algorithm> 
using namespace std; 
inline int read() { 
	int x = 0,f = 1;
	char c = getchar(); 
	while(c < '0' || c > '9')c = getchar(); 
	while(c <= '9' && c >= '0')x = x * 10 + c -'0',c = getchar(); 
	return x * f; 
} 
const int maxm = 4007; 
const int maxn  = 78; 
int C[maxm], a[maxm],b[maxm],c[maxm]; 
int loc[maxn][maxn][maxm]; 
int dp[maxn][maxn][maxm],h[maxn][maxm]; 
int n , m , num; 
void get_h(int l,int r ) { 
	for(int i = 1;i <= n;++ i) 
		for(int j = 1;j <= num;++ j) h[i][j] = 0; 
	for(int i = 1;i <= m;++ i) 
		if(l <= a[i] && r >= b[i]) 
			++ h[a[i]][1],-- h[a[i]][c[i] + 1],-- h[b[i] + 1][1],++ h[b[i] + 1][c[i] + 1];   
	for(int i = l;i <= r;++ i)   
		for(int j = 1;j <= num;++ j)  
			h[i][j] += h[i - 1][j] + h[i][j - 1] - h[i - 1][j - 1]; 
} 
int Ans[maxn]; 
void dfs(int l,int r,int k) { 
	if(r < l) return; 
	while(dp[l][r][k] <= dp[l][r][k + 1] && k < num) ++ k; 
	int Pos = loc[l][r][k]; 
	if(Pos == 0) return ; 
	Ans[Pos] = C[k]; 
	dfs(l,Pos - 1,k),dfs(Pos + 1,r,k); 
} 
int main() { 
	scanf("%d%d",&n,&m); 
	for(int i = 1;i <= m;++ i) 
		a[i] = read(),b[i] = read(),C[i] = c[i] = read(); 	
	std::sort(C + 1,C + m + 1); 
	num = unique(C + 1,C + m + 1) - C - 1; 
	for(int i = 1;i <= m;++ i) c[i] = lower_bound(C + 1,C + num + 1,c[i]) - C; 
	for(int i = 1;i <= m;++ i)  
		if(a[i] == b[i])   
			for(int j = 1;j <= c[i];++ j)   dp[a[i]][a[i]][j] += C[j]; 
	for(int i = 1;i <= n;++ i) 
		for(int j = num - 1;j; -- j) dp[i][i][j] = std::max(dp[i][i][j],dp[i][i][j + 1]);  
	for(int i = 1;i <= n; ++ i) 
		for(int j = 0;j <= num; ++ j) loc[i][i][j] = i; 	
	for(int k = 2;k <= n;++ k) { 
		for(int r, l = 1;l  + k - 1 <= n;++ l) { 
			r = l + k - 1; 
			get_h(l,r); 
			
			for(int i = num;i; --i) { 
				for(int j = l;j <= r;++ j)   
					if(dp[l][j - 1][i] + dp[j + 1][r][i] + h[j][i] * C[i] >= dp[l][r][i]) { 
						dp[l][r][i] = dp[l][j - 1][i] + dp[j + 1][r][i] + h[j][i] * C[i]; 
						loc[l][r][i] = j; 
					}  
				if(dp[l][r][i] < dp[l][r][i + 1]) { 
					dp[l][r][i] = dp[l][r][i + 1]; 
					loc[l][r][i] = loc[l][r][i + 1]; 
				} 
			}
		} 
	} 
	int ans = 1; 
	for(int i = 2;i <= num;++ i) { 
		if(dp[1][n][i] > dp[1][n][ans]) ans = i; 
	} 
	printf("%d\n",dp[1][n][ans]); 
	dfs(1,n,ans); 
	for(int i = 1;i <= n;++ i) printf("%d ",Ans[i]); 
	return 0;
} 
posted @ 2018-07-04 21:12  zzzzx  阅读(144)  评论(0编辑  收藏  举报