[BZOJ4380][POI2015]Myjnie(區間 DP )
阿新 • • 發佈:2018-11-23
Address
Solution
非常有意思的題。
先把
離散化。
定義狀態:
表示區間
內的最小值為
,從滿足
的人中獲得的最大收益。
邊界
。
轉移時列舉區間最小值所在的點
。
易得,這時候左端點在
內且右端點在
內的區間的最小值位置都是
。
統計出
表示滿足
且
,
的人有多少個。
轉移就容易得出:
其中
表示離散化前
的實際值。
記錄下
的字尾最大值,可以實現
的優秀複雜度。
輸出方案時只需要記錄
從哪個
轉移即可。
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Rof(i, a, b) for (i = a; i >= b; i--)
inline int read()
{
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 55, M = 4005;
int n, m, tmpm, a[M], b[M], c[M], tmp[M], f[N][N][M], maxf[N][N][M],
cnt[M], mid[N][N][M], midf[N][N][M];
void addto(int l, int r, int mid)
{
int i;
For (i, 1, tmpm) cnt[i] = 0;
For (i, 1, m)
if (l <= a[i] && b[i] <= r && a[i] <= mid && mid <= b[i])
cnt[c[i]]++;
}
void output(int l, int r, int x)
{
int xmid = mid[l][r][x];
if (l < xmid) output(l, xmid - 1, midf[l][xmid - 1][x]);
printf("%d ", tmp[x]);
if (xmid < r) output(xmid + 1, r, midf[xmid + 1][r][x]);
}
int main()
{
int i, j, k, h;
n = read(); m = read();
For (i, 1, m) a[i] = read(), b[i] = read(), c[i] = tmp[i] = read();
std::sort(tmp + 1, tmp + m + 1);
tmpm = std::unique(tmp + 1, tmp + m + 1) - tmp - 1;
For (i, 1, m)
c[i] = std::lower_bound(tmp + 1, tmp + tmpm + 1, c[i]) - tmp;
Rof (i, n, 1) For (j, i, n)
{
For (k, i, j)
{
addto(i, j, k);
int sum = 0;
Rof (h, tmpm, 1)
{
sum += cnt[h];
int delta = maxf[i][k - 1][h] + maxf[k + 1][j][h] + tmp[h] * sum;
if (delta > f[i][j][h] || !f[i][j][h])
f[i][j][h] = delta, mid[i][j][h] = k;
}
}
Rof (h, tmpm, 1)
if (f[i][j][h] > maxf[i][j][h + 1] || !maxf[i][j][h + 1])
maxf[i][j][h] = f[i][j][h], midf[i][j][h] = h;
else maxf[i][j][h] = maxf[i][j][h + 1],
midf[i][j][h] = midf[i][j][h + 1];
}
std::cout << maxf[1][n][1] << std::endl;
output(1, n, midf[1][n][1]);
std::cout << std::endl;
return 0;
}