zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    跟我一起写 Makefile
    NFS服务器配置
    q
    tar命令的详细解释
    etc/xinetd.d目录介绍
    ubuntu 10.04下的配置tftp服务器
    莫队板子
    Day8(分块)
    字符串板子
    字符串练习题
  • 原文地址:https://www.cnblogs.com/mmlz/p/4284968.html
Copyright © 2011-2022 走看看