zoukankan      html  css  js  c++  java
  • 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
    ", f[1][n][1]);
    59     dfs(1, n, 1);
    60     REP(i, 1, n) printf("%d%c", ans[i], i == n ? '
    ' : ' ');
    61     return 0;
    62 }
    View Code
  • 相关阅读:
    在dataGridView中实现批量删除
    VS2005制作简单的安装程序
    [WinForms]
    TreeView的联动复选框
    TreeView
    AcceptChanges()和RejectChanges()
    用C#在WINDOWS中实现新用户帐号的创建
    测试成功的窗体应用[批量新增、删除、保存]
    TreeView的递归读取
    VS2005中部署C#应用程序
  • 原文地址:https://www.cnblogs.com/-ZZB-/p/6601602.html
Copyright © 2011-2022 走看看