• 洛谷P1880 [NOI1995]石子合并 纪中21日c组T4 2119. 【2016-12-30普及组模拟】环状石子归并


     

    洛谷P1880 石子合并 纪中2119. 环状石子归并

    洛谷传送门

    题目描述1

    在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。

    试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分.

    输入格式

    数据的第1行试正整数N,1≤N≤100,表示有N堆石子.第2行有N个数,分别表示每堆石子的个数.

    输出格式

    输出共2行,第1行为最小得分,第2行为最大得分.

    输入输出样例

    输入 #1
    4
    4 5 9 4
    输出 #1
    43
    54

    (File IO): input:stone.in output:stone.out

    时间限制: 1000 ms  空间限制: 262144 KB  具体限制  

    Goto ProblemSet

    题目描述2

      在一个环状跑道上摆放着N堆石子,现在要将所有的石子有次序地合并成一堆。规定每次只能选取相邻的两堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。问最少的总得分是多少? 

    输入

    第一行为石子堆数N。
    从第2行到第N + 1行,每行一个正整数。第i个数表示第i堆石子的石子数。

    输出

    在第一行输出一个整数,表示最少的总得分。

    样例输入

    4
    4
    5
    9

    样例输出

    43 

    数据范围限制

    在40%的数据中,1 ≤ N ≤ 100
    在60%的数据中,1 ≤ N ≤ 200
    在100%的数据中,1 ≤ N ≤ 2000
    保证输入数据中每堆石子的石子数不超过10000 

    Solution

    此题为区间DP+四边形不等式

    这是我第一次见到区间DP

    洛谷上既要求最大值,也要求最小值,(多写几句话的事~)但是数据范围最大只有100

    jzoj上就恶心了,虽然只要求最小值,但是数据范围最大为2000!

    Algorithm1

    标准的区间DP

    由于这是环形的,所以要把整个跑道复制一遍

    可以在输入的同时操作

    (约定:s[i]表示第i(0~n-1)堆石子的数量)

    for(int i=0;i<n;i++) cin>>s[i],s[i+n]=s[i];

    做DP前要先弄清楚“阶段”,“状态”,“决策”;

    由于首先要合并两堆,再在两堆的基础上合并三堆,再在三堆的基础上合并四堆……以此类推。

    并且,每次要选相邻的两堆合并(这就是为什么不能像“合并果子那样使用贪心”)

    所以,每一个阶段就是合并去=的区间长度 len

    这个len在循环的最外层,从2至n(最少合并2堆)

    其次是状态

    状态即为最初的第l堆石子和第r堆石子被合并,

    同时l~r这段区间的长度为阶段——len。

    所以我们要枚举的状态就是左端点

    范围:左极限为0,右极限为右端点<n

    最内层是决策

    顾名思义:

    就是决定当前应该选哪两堆来合并

    对于目前长度为len的区间[l,r)

    可以选出一个中间点k∈[l,r)

    表示先合并了[l,k],再合并[k+1,r)

    所以决策就是中间点k

    同时还要计算合并这两堆石子所需要的体力(即为两堆石子的石子数量之和)

    可以使用前缀和计算

    Code1

    洛谷Code

     1 #include<iostream>//不想OI一场空,千万别用万能头
     2 #include<algorithm>//快排sort()
     3 #include<cstdio>//能不用cin就不用
     4 #include<cstring>
     5 #include<cmath>
     6 #include<map>
     7 #include<set>
     8 #include<vector>
     9 #include<queue>
    10 #define IL inline
    11 using namespace std;
    12 
    13 int s[201],n,minn=0x3f3f3f3f,maxn;
    14 int dpmin[201][201],dpmax[201][201];
    15 int sum[201];
    16 int main()
    17 {
    18     cin>>n;
    19     memset(dpmin,0x3f,sizeof(dpmin));
    20     for(int i=0;i<n;i++) cin>>s[i],s[i+n]=s[i];
    21     for(int i=0;i<2*n;i++)
    22         dpmin[i][i]=0;
    23     sum[0]=s[0];
    24     for(int i=1;i<2*n;i++) sum[i]=sum[i-1]+s[i];
    25     for(int len=2;len<=n;len++)
    26     {
    27         for(int l=0;l+len-1<2*n;l++)
    28         {
    29             for(int k=l;k<l+len-1;k++)
    30                 dpmin[l][l+len-1]=min(dpmin[l][l+len-1],dpmin[l][k]+dpmin[k+1][l+len-1]),
    31                 dpmax[l][l+len-1]=max(dpmax[l][l+len-1],dpmax[l][k]+dpmax[k+1][l+len-1]);
    32             dpmin[l][l+len-1]+=sum[l+len-1]-sum[l-1];
    33             dpmax[l][l+len-1]+=sum[l+len-1]-sum[l-1];
    34         }
    35     }
    36     for(int i=0;i<n;i++)
    37     minn=min(minn,dpmin[i][i+n-1]),maxn=max(maxn,dpmax[i][i+n-1]);
    38     cout<<minn<<endl<<maxn;
    39     return 0;
    40 }

    纪中Code1(70分)

     1 #include<iostream>//不想OI一场空,千万别用万能头
     2 #include<algorithm>//快排sort()
     3 #include<cstdio>//能不用cin就不用
     4 #include<cstring>
     5 #include<cmath>
     6 #include<map>
     7 #include<set>
     8 #include<vector>
     9 #include<queue>
    10 #define IL inline
    11 using namespace std;
    12 
    13 int s[4001],n,minn=0x3f3f3f3f;
    14 int f[4001][4001];
    15 int sum[4001];
    16 IL int read()
    17 {
    18     int res=0;
    19     char ch=getchar();
    20     while(ch<'0'||ch>'9')
    21         ch=getchar();
    22     while(ch>='0'&&ch<='9')
    23         res=(res<<1)+(res<<3)+(ch^48),ch=getchar();
    24     return res;
    25 }
    26 
    27 int main()
    28 {
    29 //    freopen("stone.in","r",stdin);
    30 //    freopen("stone.out","w",stdout);
    31     n=read();
    32     memset(f,0x3f,sizeof(f));
    33     for(int i=1;i<=n;i++) s[i]=read(),s[i+n]=s[i];
    34     for(int i=1;i<=2*n;i++)
    35         f[i][i]=0,sum[i]=sum[i-1]+s[i];
    36     for(int len=2;len<=n;len++)
    37     {
    38         for(int l=1;l+len-1<=2*n;l++)
    39         {
    40             for(int k=l;k<l+len-1;k++)
    41                 f[l][l+len-1]=min(f[l][l+len-1],f[l][k]+f[k+1][l+len-1]);
    42             f[l][l+len-1]+=sum[l+len-1]-sum[l-1];
    43         }
    44     }
    45     for(int i=1;i<=n;i++)
    46         minn=min(minn,f[i][i+n-1]);
    47     cout<<minn;
    48     return 0;
    49 }
    纪中Code1

    为什么折叠?

    纪中此题的范围是2000,要用到四边形不等式优化成n2才能过……毒瘤呀

    Attention1

    所有数组都要开两倍大——这是环状变链状。

    Algorithm2

    四边形不等式

    对于一个函数f(i,j),有四个值a<=b<c<=d

    使得f(a,b)+f(c,d)<f(a,c)+f(b,d)

    那么这个函数满足四边形不等式

    可以放到决策k时使用

    至于证明嘛……打表证吧

    Impression

    2019-08-22 11:51:55

    与此同时……

    哪个人知道我们听不懂今天的讲课会都回来,故意放了比赛???

  • 相关阅读:
    学习笔记4
    学习笔记2
    学习笔记1
    树莓派与Arduino串口通信
    团队大作业第三周周报
    团队大作业第二周周报
    团队大作业第一周周报
    RTCSD_第三次作业
    RTCSD_第二次作业
    RTCSD_第一次作业
  • 原文地址:https://www.cnblogs.com/send-off-a-friend/p/11392888.html
Copyright © 2020-2023  润新知