• 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
    ", 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 }
    View Code
  • 相关阅读:
    【OpenCV学习】XML的读写
    【学术研究基础】聚类分析学习
    【OpenCV学习】Laplace变换(视频边界检测)
    【OpenCV学习】DFT变换
    【英语天天读】生命的起跑线
    【OpenCV学习】yml的读取
    【OpenCV学习】Kmean均值聚类对图片进行减色处理
    【英语天天读】born to win
    WinFrom 中 label背景透明
    dev GridControl双击行事件
  • 原文地址:https://www.cnblogs.com/cychester/p/9841074.html
Copyright © 2020-2023  润新知