• BZOJ 3982 Stacking Plates 解题报告


    我们首先可以得到:如果有一堆盘子里有一些相邻的盘子的直径相等,那么自然这些盘子可以统一处理,就可以缩成一个了。

    然后我们接着考虑给每一堆盘子都染上一种颜色,那么操作的次数 step = diff * 2 - n + 1

    其中 diff 表示最终的盘子堆中相邻的盘子的颜色不同的对数。

    接着我们可以将盘子的直径离散化。

    那么我们可以考虑Dp,设 Dp[s][i] 为处理完所有盘子直径小于等于 s 的盘子,并且最底下的盘子的颜色是 i 的 diff 的最小值。

    至于转移的话呢,记直径为 s 的盘子个数为 tot[s],然后找到所有直径为 s 的盘子及其颜色 i ,那么就有:

    • res1 = min(Dp[s - 1][j] + tot[s]) (j = 1 ~ n)
    • res2 = min(Dp[s - 1][k] + tot[s] - 1) (存在一个直径为 s,颜色为 k 的盘子)
    • Dp[s][i] = min(res1, res2)

    初始化 Dp[0][i] = 0 (i = 1 ~ n)

    答案 ans = min(Dp[Max_s][i]) * 2 - n + 1 

    于是就做完啦~

    毕竟 Gromah 太弱,只会做水题。

     1 #include <cmath>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <iostream>
     5 #include <algorithm>
     6 using namespace std;
     7 #define N 50 + 5
     8 #define M 2500 + 5
     9 #define SIZE 10000 + 5
    10 #define INF 593119681
    11 
    12 int _, n;
    13 int A[N][N];
    14 int Size[N], Point[N], T[N];
    15 int Dp[2][N];
    16 int S[SIZE];
    17 
    18 inline void Init()
    19 {
    20     memset(S, 0, sizeof(S));
    21     for (int i = 1; i <= n; i ++)
    22     {
    23         scanf("%d", Size + i);
    24         for (int j = 1; j <= Size[i]; j ++)
    25         {
    26             scanf("%d", A[i] + j);
    27             S[A[i][j]] = 1;
    28         }
    29         Size[i] = unique(A[i] + 1, A[i] + Size[i] + 1) - A[i] - 1;
    30         Point[i] = 1;
    31     }
    32     for (int i = 1; i < SIZE; i ++)
    33         S[i] += S[i - 1];
    34     for (int i = 1; i <= n; i ++)
    35         for (int j = 1; j <= Size[i]; j ++)
    36             A[i][j] = S[A[i][j]];
    37 }
    38 
    39 inline void Solve()
    40 {
    41     printf("Case %d: ", ++ _);
    42     for (int i = 0; i <= n; i ++)
    43         Dp[0][i] = 0;
    44     for (int i = 1; i <= S[SIZE - 1]; i ++)
    45     {
    46         T[0] = 0;
    47         Dp[1][0] = INF;
    48         for (int j = 1; j <= n; j ++)
    49         {
    50             if (A[j][Point[j]] == i)
    51                 T[++ T[0]] = j, Point[j] ++;
    52             Dp[1][j] = INF;
    53         }
    54         for (int j = 1; j <= T[0]; j ++)
    55         {
    56             for (int k = 1; k <= T[0]; k ++)
    57             {
    58                 if (j == k && T[0] > 1) continue ;
    59                 Dp[1][T[k]] = min(Dp[1][T[k]], Dp[0][T[j]] + T[0] - 1);
    60             }
    61             for (int k = 0; k <= n; k ++)
    62                 Dp[1][T[j]] = min(Dp[1][T[j]], Dp[0][k] + T[0]);
    63         }
    64         for (int j = 0; j <= n; j ++)
    65             Dp[0][j] = Dp[1][j];
    66     }
    67     int Min = INF;
    68     for (int i = 0; i <= n; i ++)
    69         Min = min(Min, Dp[0][i]);
    70     printf("%d
    ", Min * 2 - n + 1);
    71 }
    72 
    73 int main()
    74 {
    75     #ifndef ONLINE_JUDGE
    76         freopen("3982.in", "r", stdin);
    77         freopen("3982.out", "w", stdout);
    78     #endif
    79     
    80     while (scanf("%d", &n) == 1)
    81     {
    82         Init();
    83         Solve();
    84     }
    85     
    86     #ifndef ONLINE_JUDGE
    87         fclose(stdin);
    88         fclose(stdout);
    89     #endif
    90     return 0;
    91 }
  • 相关阅读:
    Python小白的数学建模 ---- 系列课程
    Maven学习笔记
    JavaScript 中的 Var,Let 和 Const 有什么区别
    (鸡汤文)搞懂了 JavaScript 定时器 setTimeout() 的 this 指向!
    setTimeout返回值的验证,(〒︿〒) 请原谅我一直以来对你的忽视
    终于把初中到大学的数学知识梳理完了(学习算法必备数学知识)
    最简单入门深度学习
    机器学习基本流程
    Vue.js源码解析-Vue初始化流程
    最大公约数&最小公倍数
  • 原文地址:https://www.cnblogs.com/gromah/p/4424405.html
Copyright © 2020-2023  润新知