• BZOJ3229 石子合并


     

    Description

      在一个操场上摆放着一排N堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。
      试设计一个算法,计算出将N堆石子合并成一堆的最小得分。
     

    Input

      第一行是一个数N。
      以下N行每行一个数A,表示石子数目。
     

    Output

      共一个数,即N堆石子合并成一堆的最小得分。

     

    Sample Input

    4
    1
    1
    1
    1

    Sample Output

    8

    HINT

     

    对于 100% 的数据,1≤N≤40000

    对于 100% 的数据,1≤A≤200

     
     
    正解:GarsiaWachs算法
    解题报告:
      神奇的算法,居然可以把石子合并做到O(NlogN),不可思议,感到害怕。
      上午讲题的时候提到了用四边形不等式得出的可以有单调性的N^2的优化DP,然而面对40000的数据还是有一点虚。
      移步学习GarsiaWachs算法:http://www.cnblogs.com/lwq12138/p/5425465.html 或者 http://blog.csdn.net/Regina8023/article/details/45244733
      不详细讲了。
     
     1 //It is made by jump~
     2 #include <iostream>
     3 #include <cstdlib>
     4 #include <cstring>
     5 #include <cstdio>
     6 #include <cmath>
     7 #include <algorithm>
     8 #include <ctime>
     9 #include <vector>
    10 #include <queue>
    11 #include <map>
    12 #include <set>
    13 #ifdef WIN32   
    14 #define OT "%I64d"
    15 #else
    16 #define OT "%lld"
    17 #endif
    18 using namespace std;
    19 typedef long long LL;
    20 const int inf = 5201314;
    21 const int MAXN = 40011;
    22 int a[MAXN];
    23 int n;
    24 LL ans;
    25 
    26 inline int getint()
    27 {
    28        int w=0,q=0;
    29        char c=getchar();
    30        while((c<'0' || c>'9') && c!='-') c=getchar();
    31        if (c=='-')  q=1, c=getchar();
    32        while (c>='0' && c<='9') w=w*10+c-'0', c=getchar();
    33        return q ? -w : w;
    34 }
    35 
    36 inline void work(){
    37     n=getint();
    38     for(int i=1;i<=n;i++) a[i]=getint();
    39     int m=n;
    40     a[0]=a[n+1]=inf;
    41     for(int i=1;i<n;i++) {//最后一次不用做
    42     int k;
    43     for(int j=1;j<=m;j++) {//从左往右,每次找到第一个满足a[k−1]≤a[k+1]的k,然后合并a[k−1],a[k]
    44         if(a[j-1]<a[j+1]) { k=j; break; }
    45     }
    46     a[k-1]+=a[k];
    47     for(int j=k;j<m;j++) a[j]=a[j+1];//左移
    48     ans+=a[k-1]; k--;//指向当前处理结点
    49     while(k>0 && a[k-1]<=a[k]) { //从当前位置开始向左找第一个a[j]>a[k−1]+a[k]的j,把合并后的值插到j的后面
    50         swap(a[k-1],a[k]);
    51         k--;
    52     }
    53     a[m]=inf;
    54     m--;
    55     }
    56     printf(OT,ans);
    57 }
    58 
    59 int main()
    60 {
    61   work();
    62   return 0;
    63 }
  • 相关阅读:
    【C语言】学习笔记9——结构struct(2)
    WPF dev 获取gridControl筛选后的数据
    WPF DEV dxc:ChartControl 柱状图
    WPF 重写ListBox(透明效果)
    WPF 后台重写 DataTemplate
    WPF 去掉Drag a column header here to group by that column
    c# 对DataTable进行分组group by
    c# ref与out用法
    WPF canvas设置旋转角度和偏移位置
    WPF 流加载
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/5664314.html
Copyright © 2020-2023  润新知