zoukankan      html  css  js  c++  java
  • 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
    ",dp[1][n][ans]); 
    	dfs(1,n,ans); 
    	for(int i = 1;i <= n;++ i) printf("%d ",Ans[i]); 
    	return 0;
    } 
    
  • 相关阅读:
    算法学习:二分法从入门到精通
    TypeScript筑基笔记一:Visual Studio Code 创建Typescript文件和实时监控
    LeetCode 92. 反转链表 II
    LeetCode 1525. 字符串的好分割数目
    字节跳动-people后台一面面经
    LeetCode 117. 填充每个节点的下一个右侧节点指针 II
    LeetCode 1529. 灯泡开关 IV
    LeetCode 165. 比较版本号
    LeetCode 312. 戳气球
    LeetCode 605. 种花问题
  • 原文地址:https://www.cnblogs.com/sssy/p/9265359.html
Copyright © 2011-2022 走看看