BZOJ 4380 Myjnie 区间DP
4380: [POI2015]Myjnie
Time Limit: 40 Sec Memory Limit: 256 MBSec Special JudgeSubmit: 162 Solved: 82
[Submit][Status][Discuss]
Description
有n家洗车店从左往右排成一排,每家店都有一个正整数价格p[i]。
有m个人要来消费,第i个人会驶过第a[i]个开始一直到第b[i]个洗车店,且会选择这些店中最便宜的一个进行一次消费。但是如果这个最便宜的价格大于c[i],那么这个人就不洗车了。
请给每家店指定一个价格,使得所有人花的钱的总和最大。
Input
第一行包含两个正整数n,m(1<=n<=50,1<=m<=4000)。
接下来m行,每行包含三个正整数a[i],b[i],c[i](1<=a[i]<=b[i]<=n,1<=c[i]<=500000)
Output
第一行输出一个正整数,即消费总额的最大值。
第二行输出n个正整数,依次表示每家洗车店的价格p[i],要求1<=p[i]<=500000。
若有多组最优解,输出任意一组。
Sample Input
7 5
1 4 7
3 7 13
5 6 20
6 7 1
1 2 5
1 4 7
3 7 13
5 6 20
6 7 1
1 2 5
Sample Output
43
5 5 13 13 20 20 13
5 5 13 13 20 20 13
HINT
Source
Solution
这个区间DP的思路十分神奇。
设G[l][r][i]为区间[l, r]中最小值为k的最优值,F[l][r][i] = max{G[l][r][j]} (j >= i)。
转移:F[l][r][i] = max{F[l][k-1]+F[k+1][r]+c[i]*cnt[k][i]} (cnt[k][i]就是指c[j]>=i且在区间[l,r]中且跨越点k的个数)
对于方案的记录,我们只需要在转移的时候记录,最后再从最优解开始dfs就可以了。
但是千万要注意的是,所有合法的情况初始化为-INF。不这样做的话,就构不出方案,把f转为0的时候就把方案给记录下来了。
Code
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <string> 5 #include <algorithm> 6 7 using namespace std; 8 9 #define FIO "a" 10 #define REP(i, a, b) for (int i = (a), i##_end_ = (b); i <= i##_end_; ++i) 11 #define DWN(i, a, b) for (int i = (a), i##_end_ = (b); i >= i##_end_; --i) 12 #define mset(a, b) memset(a, b, sizeof(a)) 13 const int maxn = 55, maxm = 4005, INF = 0x3fffffff; 14 int n, m, a[maxm], b[maxm], c[maxm]; 15 int t[maxm], t_cnt; 16 int f[maxn][maxn][maxm], cnt[maxn][maxm], from[maxn][maxn][maxn], las[maxn][maxn][maxn]; 17 int ans[maxn]; 18 19 void dfs(int l, int r, int k) 20 { 21 if (l > r) return ; 22 ans[from[l][r][k]] = t[las[l][r][k]]; 23 dfs(l, from[l][r][k]-1, las[l][r][k]); 24 dfs(from[l][r][k]+1, r, las[l][r][k]); 25 } 26 27 int main() 28 { 29 // freopen(FIO ".in", "r", stdin); 30 // freopen(FIO ".out", "w", stdout); 31 scanf("%d %d", &n, &m); 32 t_cnt = 0; 33 REP(i, 1, m) scanf("%d %d %d", &a[i], &b[i], &c[i]), t[++t_cnt] = c[i]; 34 sort(t+1, t+t_cnt+1); 35 int temp = t_cnt, x; t_cnt = 0; 36 REP(i, 1, temp) if (t[i] != t[i-1]) t[++t_cnt] = t[i]; 37 REP(i, 1, m) c[i] = lower_bound(t+1, t+t_cnt+1, c[i])-t; 38 REP(i, 1, n) REP(j, i, n) REP(k, 1, m) f[i][j][k] = -INF; 39 REP(len, 1, n) 40 REP(l, 1, n-len+1) 41 { 42 int r = l+len-1; 43 REP(i, l, r) REP(j, 1, m) cnt[i][j] = 0; 44 REP(i, 1, m) 45 if (a[i] >= l && b[i] <= r) 46 REP(j, a[i], b[i]) cnt[j][c[i]] ++; 47 REP(i, l, r) DWN(j, m-1, 1) cnt[i][j] += cnt[i][j+1]; 48 REP(k, l, r) 49 REP(i, 1, m) 50 if (f[l][k-1][i]+f[k+1][r][i]+t[i]*cnt[k][i] > f[l][r][i]) 51 f[l][r][i] = f[l][k-1][i]+f[k+1][r][i]+t[i]*cnt[k][i], 52 from[l][r][i] = k, las[l][r][i] = i; 53 DWN(i, m-1, 1) 54 if (f[l][r][i] < f[l][r][i+1]) 55 f[l][r][i] = f[l][r][i+1], 56 from[l][r][i] = from[l][r][i+1], las[l][r][i] = las[l][r][i+1]; 57 } 58 printf("%d\n", f[1][n][1]); 59 dfs(1, n, 1); 60 REP(i, 1, n) printf("%d%c", ans[i], i == n ? '\n' : ' '); 61 return 0; 62 }
Nothing is impossible!