码迷,mamicode.com
首页 > 其他好文 > 详细

luogu P3592 [POI2015]MYJ

时间:2018-07-04 21:37:24      阅读:199      评论:0      收藏:0      [点我收藏+]

标签:cpp   最小值   www.   getch   poi   problem   getc   int   输出   

题目链接

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;
} 

luogu P3592 [POI2015]MYJ

标签:cpp   最小值   www.   getch   poi   problem   getc   int   输出   

原文地址:https://www.cnblogs.com/sssy/p/9265359.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!