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