• BZOJ 3971 Матрёшка 解题报告


    很自然想到区间 DP。

    设 $Dp[i][j]$ 表示把区间 $[i, j]$ 内的套娃合并成一个所需要的代价,那么有:

    • $Dp[i][i] = 0$
    • $Dp[i][j] = min{Dp[i][k] + Dp[k + 1][j] + Merge([i, k], [k + 1, j])} (i le k < j)$

    于是问题在于算 $Merge([a, b], [c, d])$。

    我们考虑一下:区间 $[a, b]$ 内的哪些套娃是需要打开的:

    是不是 $[a, b]$ 中所有大于 $[c, d]$ 中最小的套娃都需要打开,来装 $[c, d]$ 中最小的套娃呢?

    $[c, d]$ 同理。

    于是我们可以预处理 $Sum[i][x]$ 为在前 $i$ 个套娃中,大小 $le x$ 的套娃的个数,

    那么就可以 $O(1)$ 地算 $Merge([a, b], [c, d])$ 了。

    有一个问题,如果在 $[a, b]$、$[c, d]$ 中有相同大小的套娃怎么办?

    不着急,先往下看。

    处理完 $Dp[i][j]$ 后,我们再设立一个 $F[i]$ 表示把前 $i$ 个套娃装成若干个完好的套娃集所需代价的最小值,那么就有:

    • $F[i] = min(F[j] + Dp[j + 1][i]) (mex([j + 1, i]) = i - j + 1)$
    • $mex([u, v]) = min(x) (x otin {A_u, A_{u+1}, dots, A_v})$

    当然,如果不能找到合法的转移点,那么令 $F[i] = INF$。

    然后对于一个合法的方案,不可能出现相同大小的套娃被装进同一个套娃内的情况,

    所以 $[a, b]$、$[c, d]$ 中有相同大小的套娃的话,那么这个区间一定不合法,所以我们大可不必考虑那么多了。

    于是最后看 $F[n]$ 就可以了。令 $M = max{A_i}$

    时间复杂度 $O(n^3 + n^2M)$,空间复杂度 $O(n^2 + nM)$。

     1 #include <cmath>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <iostream>
     5 #include <algorithm>
     6 using namespace std;
     7 #define N 500 + 5
     8 #define INF 593119681
     9 
    10 int n, Max;
    11 int A[N], _Dp[N], T[N];
    12 int Sum[N][N], Dp[N][N], Mex[N][N], Min[N][N];
    13 
    14 inline void Prepare()
    15 {
    16     for (int i = 1; i <= n; i ++)
    17         Sum[i][A[i]] ++;
    18     for (int i = 1; i <= n; i ++)
    19         for (int j = 1; j <= Max; j ++)
    20             Sum[i][j] += Sum[i][j - 1] + Sum[i - 1][j] - Sum[i - 1][j - 1];
    21     
    22     for (int i = 1; i <= n; i ++)
    23     {
    24         for (int j = 1; j <= Max; T[j ++] = 0) ;
    25         for (int j = i; j <= n; j ++)
    26         {
    27             T[A[j]] ++;
    28             for (Mex[i][j] = 1; T[Mex[i][j]]; Mex[i][j] ++) ;
    29             Min[i][j] = i == j ? A[i] : min(Min[i][j - 1], A[j]);
    30         }
    31     }
    32 }
    33 
    34 inline int Calc(int l, int mid, int r)
    35 {
    36     int min_1 = Min[l][mid], res = Sum[r][Max] - Sum[mid][Max] - Sum[r][min_1] + Sum[mid][min_1];
    37     min_1 = Min[mid + 1][r], res += Sum[mid][Max] - Sum[l - 1][Max] - Sum[mid][min_1] + Sum[l - 1][min_1];
    38     return res;
    39 }
    40 
    41 int main()
    42 {
    43     #ifndef ONLINE_JUDGE
    44         freopen("3971.in", "r", stdin);
    45         freopen("3971.out", "w", stdout);
    46     #endif
    47     
    48     scanf("%d", &n);
    49     for (int i = 1; i <= n; i ++)
    50     {
    51         scanf("%d", A + i);
    52         Max = max(Max, A[i]);
    53     }
    54     Prepare();
    55     for (int len = 0; len < n; len ++)
    56         for (int s = 1; s + len <= n; s ++)
    57         {
    58             int i = s, j = s + len;
    59             if (i == j) Dp[i][j] = 0;
    60             else
    61             {
    62                 Dp[i][j] = INF;
    63                 for (int k = i; k < j; k ++)
    64                     Dp[i][j] = min(Dp[i][j], Dp[i][k] + Dp[k + 1][j] + Calc(i, k, j));
    65             }
    66         }
    67     for (int i = 1; i <= n; i ++) _Dp[i] = INF;
    68     for (int i = 1; i <= n; i ++)
    69         for (int j = 0; j < i; j ++)
    70             if (Mex[j + 1][i] == i - j + 1)
    71                 _Dp[i] = min(_Dp[i], _Dp[j] + Dp[j + 1][i]);
    72     if (_Dp[n] >= INF) puts("Impossible");
    73         else printf("%d
    ", _Dp[n]);
    74     
    75     #ifndef ONLINE_JUDGE
    76         fclose(stdin);
    77         fclose(stdout);
    78     #endif
    79     return 0;
    80 }
    3971_Gromah
  • 相关阅读:
    .net web mvc 权限验证
    .net web api 权限验证
    LeetCode-1021 Remove Outermost Parentheses Solution(with Java)
    LeetCode-682 Baseball Game Solution (with Java)
    LeetCode-859 Buddy Strings Solution (with Java)
    LeetCode-917 Reverse Only Letters Solution (with Java)
    LeetCode-521 Longest Uncommon Subsequence I Solution (with Java)
    LeetCode-937 Reorder Data in Log Files Solution (with Java)
    LeetCode-1 Two Sum Solution (with Java)
    LeetCode-985 Sum of Even Numbers After Queries Solution (with Java)
  • 原文地址:https://www.cnblogs.com/gromah/p/4427996.html
Copyright © 2020-2023  润新知