BZOJ4380 Myjnie / Luogu3592 [POI2015]MYJ-区间DP
Description
有$n$家洗车店从左往右排成一排,每家店都有一个正整数价格$p[i]$。
有$m$个人要来消费,第$i$个人会驶过第$a[i]$个开始一直到第$b[i]$个洗车店,且会选择这些店中最便宜的一个进行一次消费。但是如果这个最便宜的价格大于$c[i]$,那么这个人就不洗车了。
请给每家店指定一个价格,使得所有人花的钱的总和最大。
Solution
神仙$DP$ QAQ
每个店的价格肯定是$c_i$中的某一个值, 所以可以离散化
定义状态 $dp[L][R][k]$ 表示 在区间$[i,j]$ 最小值为$k$ 时所能收益的最大值
转移 : $dp[L][R][k] = \max{(dp[L][i - 1][k] + dp[i + 1][R][k] + cnt[i][k])}$
但是发现这样无法快速求出答案, 所以把$dp[L][R][k]$定义为 最小值 $>=k$时所能收益的最大值。
则多了一个转移: $dp[L][R][k] = \max{(dp[L][R][k], dp[L][R][k + 1])}$。
题目要求 求出方案, 则定义$val[L][R][k]$ 为真正的$k$值, $P[L][R][k]$ 为哪个位置取 $k$
最后递归求方案
空间复杂度$O(N^2M)$, 时间复杂度$O(N^3M)$
Code
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define N 55 5 #define M 4005 6 #define rd read() 7 using namespace std; 8 9 int n, m; 10 int dp[N][N][M], cnt[N][M], val[N][N][M], P[N][N][M]; 11 int ls[M], tot, ans[N]; 12 13 struct node { 14 int l, r, val; 15 }a[M]; 16 17 inline int read() { 18 int X = 0, p = 1; char c = getchar(); 19 for (; c > '9' || c < '0'; c = getchar()) 20 if (c == '-') p = -1; 21 for (; c >= '0' && c <= '9'; c = getchar()) 22 X = X * 10 + c - '0'; 23 return X * p; 24 } 25 26 int fd(int x) { 27 return lower_bound(ls + 1, ls + 1 + tot, x) - ls; 28 } 29 30 void cmax(int &A, int B) { 31 if (A < B) 32 A = B; 33 } 34 35 void DP(int L, int R) { 36 memset(cnt, 0, sizeof(cnt)); 37 for (int i = 1; i <= m; ++i) { 38 if (a[i].l < L || a[i].r > R) 39 continue; 40 for (int j = a[i].l; j <= a[i].r; ++j) 41 cnt[j][a[i].val]++; 42 } 43 for (int i = L; i <= R; ++i) 44 for (int j = tot - 1; j; --j) 45 cnt[i][j] += cnt[i][j + 1]; 46 for (int i = tot; i; --i) { 47 int maxn = -1, pos = 0; 48 for (int j = L; j <= R; ++j) { 49 int res = dp[L][j - 1][i] + dp[j + 1][R][i] + cnt[j][i] * ls[i]; 50 if (res > maxn) 51 maxn = res, pos = j; 52 cmax(dp[L][R][i], res); 53 } 54 val[L][R][i] = i; 55 P[L][R][i] = pos; 56 if(i < m && dp[L][R][i] < dp[L][R][i + 1]) 57 val[L][R][i] = val[L][R][i + 1], 58 dp[L][R][i] = dp[L][R][i + 1], 59 P[L][R][i] = P[L][R][i + 1]; 60 } 61 } 62 63 void findans(int L, int R, int lim) { 64 if (L > R) return; 65 int fin = val[L][R][lim], pos = P[L][R][lim]; 66 ans[pos] = fin; 67 findans(L, pos - 1, fin); 68 findans(pos + 1, R, fin); 69 } 70 71 int main() 72 { 73 n = rd; m = rd; 74 for (int i = 1; i <= m; ++i) { 75 a[i].l = rd; a[i].r = rd; a[i].val = rd; 76 ls[++tot] = a[i].val; 77 } 78 sort(ls + 1, ls + 1 + tot); 79 tot = unique(ls + 1, ls + 1 + tot) - ls - 1; 80 for (int i = 1; i <= m; ++i) 81 a[i].val = fd(a[i].val); 82 for (int i = n; i; --i) 83 for (int j = i; j <= n; ++j) 84 DP(i, j); 85 printf("%d\n", dp[1][n][1]); 86 findans(1, n, 1); 87 for (int i = 1; i <= n; ++i) 88 printf("%d ", ls[ans[i]]); 89 puts(""); 90 }