• BZOJ 1200 木梳


    Description

     

    Input

    第一行为整数L,其中4≤L≤100000,且有50%的数据满足L≤104,表示木板下侧直线段的长。第二行为L个正整数A1,A2,…,AL,其中Ai≤108

    Output

    仅包含一个整数D,表示为使梳子面积最大,需要从木板上挖掉的格子数。

    Sample Input

    9
    4 4 6 5 4 2 3 3 5

    Sample Output

    3

    HINT

    初看此题,这不是一道很水很水的dp题吗,一看数据范围马上枪毙。然后就放肆想,思考一下午未果,打了一发卡决策的dp,50分果断wa。最后还是研究题解去了。
    贪心我看了很久,还是不会证明,理性的想想算了——对于某个木板的最优决策,一定存在|i-j|<=1,|b[i]-a[j]|<=2(其中b[i]指剪断后的木板高,a[i]指原木板高)。假设他是对的,那么我们dp的复杂度就会降到O(kL),其中k是一个很小的常数。
    我把证明发到这里(提取码:055a),如果你看懂,我也欢迎你跟我讨论一下。
    代码可能与网上其他题解的雷同,很正常,因为我是copy懂的。
     
     1 #include<cstring>
     2 #include<algorithm>
     3 #include<cstdio>
     4 #include<cstdlib>
     5 using namespace std;
     6 
     7 #define inf (1LL<<60)
     8 #define maxn 100010
     9 typedef long long ll;
    10 int h[maxn],pp[maxn][32],n; ll f[maxn][2][32],ans=inf,sum;
    11 
    12 int main()
    13 {
    14     freopen("1200.in","r",stdin);
    15     freopen("1200.out","w",stdout);
    16     scanf("%d",&n);
    17     for (int i = 1;i <= n;++i)
    18     {
    19         scanf("%d",h+i); sum += h[i];
    20         for (int j = h[i] - 1;j <= h[i] + 1;++j)
    21         {
    22             pp[i][++pp[i][0]] = j;
    23             if (i-1) pp[i-1][++pp[i-1][0]] = j;
    24             if (i-2) pp[i-2][++pp[i-2][0]] = j;
    25             if (i + 1 <= n) pp[i+1][++pp[i+1][0]] = j;
    26             if (i + 2 <= n) pp[i+2][++pp[i+2][0]] = j;
    27         }
    28     }
    29     for (int i = 1;i <= n;++i)
    30     {
    31         sort(pp[i]+1,pp[i]+pp[i][0]+1);
    32         pp[i][0] = unique(pp[i]+1,pp[i]+pp[i][0]+1)-pp[i]-1;
    33         while (pp[i][0] && pp[i][pp[i][0]] > h[i]) --pp[i][0];
    34     }
    35     memset(f,128,sizeof(f));
    36     for (int i = 1;i <= pp[1][0];++i) f[1][0][i] = f[1][1][i] = pp[1][i];
    37     for (int i = 2;i <= n;++i)
    38         for (int j = 1;j <= pp[i-1][0];++j)
    39             for (int k = 1;k <= pp[i][0];++k)
    40             {
    41                 if (pp[i-1][j]<pp[i][k])
    42                     f[i][0][k] = max(f[i][0][k],f[i-1][1][j]+pp[i][k]);
    43                 else if (pp[i-1][j]>pp[i][k])
    44                     f[i][1][k] = max(f[i][1][k],f[i-1][0][j]+pp[i][k]);
    45                 else
    46                 {
    47                     f[i][0][k] = max(f[i][0][k],f[i-1][0][j]+pp[i][k]);
    48                     f[i][1][k] = max(f[i][1][k],f[i-1][1][j]+pp[i][k]);
    49                 }
    50             }
    51     ans = 1LL<<60;
    52     for (int p = 0;p < 2;++p)
    53         for (int j = 1;j <= pp[n][0];++j)
    54             ans = min(ans,sum-f[n][p][j]);
    55     printf("%lld",ans);
    56     fclose(stdin); fclose(stdout);
    57     return 0;
    58 }
    View Code
  • 相关阅读:
    记一道乘法&加法线段树(模版题)
    2021CCPC网络赛(重赛)题解
    Codeforces Round #747 (Div. 2)题解
    F. Mattress Run 题解
    Codeforces Round #744 (Div. 3) G题题解
    AtCoder Beginner Contest 220部分题(G,H)题解
    Educational Codeforces Round 114 (Rated for Div. 2)题解
    Codeforces Global Round 16题解
    Educational Codeforces Round 113 (Rated for Div. 2)题解
    AtCoder Beginner Contest 182 F
  • 原文地址:https://www.cnblogs.com/mmlz/p/4284968.html
Copyright © 2020-2023  润新知