zoukankan      html  css  js  c++  java
  • P1880 [NOI1995]石子合并【区间dp】

    P1880 [NOI1995]石子合并

    提交 42.29k
    通过 19.06k
    时间限制 1.00s
    内存限制 125.00MB
    题目提供者 JosephZheng
    历史分数100

    提交记录

    查看算法标签
    进入讨论版

    相关讨论

     
    查看讨论

    推荐题目

     
    查看推荐
     

    展开

    题目描述

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

    试设计出一个算法,计算出将 NNN 堆石子合并成 111 堆的最小得分和最大得分。

    输入格式

    数据的第 111 行是正整数 NNN,表示有N堆石子。

    222 行有 NNN 个整数,第 iii 个整数 aia_iai 表示第 iii 堆石子的个数。

    输出格式

    输出共 222 行,第 111 行为最小得分,第 222 行为最大得分。

    输入输出样例

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

    说明/提示

    1≤N≤1001leq Nleq 1001N100,0≤ai≤200leq a_ileq 200ai20。

    思路

      区间DP,化链为环,在1~n的区间长度内枚举区间左右端点,在 i~j 的范围内枚举分割线k;

      转移方程:

      min_f[i][j] = min(min_f[i][j], min_f[i][k]  +  min_f[k + 1][ j ]  +  sum[ j ]  -  sum[ i-1]);
           max_f[i][j] = max(max_f[i][j], max_f[i][k]  +  max_f[k + 1][ j ]  +  sum[ j ]  -  sum[ i-1 ]);

    CODE

     1 #include <bits/stdc++.h>
     2 #define dbg(x) cout << #x << "=" << x << endl
     3 
     4 using namespace std;
     5 using LL = long long;
     6 
     7 template<class T>inline void read(T &res)
     8 {
     9     char c;T flag=1;
    10     while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
    11     while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
    12 }
    13 
    14 namespace _buff {
    15     const size_t BUFF = 1 << 19;
    16     char ibuf[BUFF], *ib = ibuf, *ie = ibuf;
    17     char getc() {
    18         if (ib == ie) {
    19             ib = ibuf;
    20             ie = ibuf + fread(ibuf, 1, BUFF, stdin);
    21         }
    22         return ib == ie ? -1 : *ib++;
    23     }
    24 }
    25 
    26 int qread() {
    27     using namespace _buff;
    28     int ret = 0;
    29     bool pos = true;
    30     char c = getc();
    31     for (; (c < '0' || c > '9') && c != '-'; c = getc()) {
    32         assert(~c);
    33     }
    34     if (c == '-') {
    35         pos = false;
    36         c = getc();
    37     }
    38     for (; c >= '0' && c <= '9'; c = getc()) {
    39         ret = (ret << 3) + (ret << 1) + (c ^ 48);
    40     }
    41     return pos ? ret : -ret;
    42 }
    43 
    44 const int maxn = 1e5 + 7;
    45 const int inf  = 0x3f3f3f3f;
    46 
    47 int n;
    48 int a[maxn];
    49 int min_f[207][207];
    50 int max_f[207][207];
    51 int sum[maxn];
    52 
    53 int main()
    54 {
    55     read(n);
    56     for(int i = 1; i <= n; ++i) {
    57         read(a[i]);
    58         a[i+n] = a[i];
    59     }
    60     int m = n * 2;
    61     for(int i = 1; i <= m; ++i) {
    62         sum[i] = sum[i-1] + a[i];
    63         //printf("sum[%d]:%d
    ",i,sum[i]);
    64     }
    65     memset(min_f, inf, sizeof(min_f));
    66 
    67     for(int i = 1; i <= m; ++i) {
    68         min_f[i][i] = 0;
    69     }
    70     for(int len = 2; len <= n; ++len) {///长度
    71         for(int i = 1; i <= m-len+1; ++i) {///
    72             int j = i + len - 1;///
    73             for(int k = i; k < j; ++k) {///分割
    74                 min_f[i][j] = min(min_f[i][j], min_f[i][k]+min_f[k+1][j]+sum[j]-sum[i-1]);
    75                 max_f[i][j] = max(max_f[i][j], max_f[i][k]+max_f[k+1][j]+sum[j]-sum[i-1]);
    76             }
    77         }
    78     }
    79     int minn = 0x7fffffff, maxx = -1;
    80     for(int i = 1; i <= n; ++i) {
    81         minn = min(min_f[i][i+n-1],minn);
    82         maxx = max(max_f[i][i+n-1],maxx);
    83     }
    84     printf("%d
    %d
    ",minn,maxx);
    85     return 0;
    86 }
    View Code
  • 相关阅读:
    后缀名文件说明
    转行小白成长路-java篇
    转行小白成长路-java篇
    转行小白成长路-java篇
    转行小白成长路-java篇
    转行小白成长路-java篇
    转行小白成长路-java篇
    转行小白成长路-java篇
    转行小白成长路-java篇
    转行小白成长路-java篇
  • 原文地址:https://www.cnblogs.com/orangeko/p/12293475.html
Copyright © 2011-2022 走看看