BZOJ 4380 Myjnie 区间DP

4380: [POI2015]Myjnie

Time Limit: 40 Sec  Memory Limit: 256 MBSec  Special Judge
Submit: 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

Sample Output

43
5 5 13 13 20 20 13

HINT

Source

鸣谢Claris

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 }
View Code

 

posted @ 2017-03-22 19:21  Splay  阅读(244)  评论(0编辑  收藏  举报