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≤1001\leq N\leq 1001N100,0≤ai≤200\leq a_i\leq 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\n",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\n%d\n",minn,maxx);
85     return 0;
86 }
View Code

 

全部评论

相关推荐

头像
11-03 16:48
已编辑
百度_高级研发工程师
事实是检验真理的唯一标准。&nbsp;无论我们怎么去说,去讲述,去证明,都抵不过一个offer来得实在,无论我们怎么去复现求职中的摸爬滚打、扒皮抽筋、狼狈不堪,都抵不过你在简历写上大厂的名字(外包不算)。&nbsp;所以在我求职期间,我什么话都不说,什么话都不讲,因为没有意义,虽然我总讲过程才是意义,但只有当你上岸的那一刻,你才有资格回想在水里的挣扎,只有等你出了山,你才知道山的全貌。&nbsp;我为什么一定要离开华为OD,难道它不稳定吗,不能赚钱吗。为了证明自己,那肯定有的。其实更多的是印证我的认知是否真的正确。&nbsp;(给不了解我的人交代一下背景,在下双非一本,gap一年,华为OD外包,摸爬滚打4个月,艰难上岸百度正编)一、...
先锋战士:说得很真诚。鄙视链自古有之,学历,家庭背景,财富,权利。从小有之,小学羡慕那些当班委的,中学羡慕那些学生会的,高中羡慕尖子班拿教学金的,大学羡慕高绩点,毕业了羡慕进大厂的。工作了,又羡慕高职级的,再后来又羡慕别人早早结婚的。我想表达的观点很简单,无论是华为od还是百度,都是经历,没有孰高孰低,为了抵达下一个风景,总会付出更多东西,但不就是人生吗?正如登山,每个阶段的山,都要想办法攀登,在博主的文字中,见到了坚持和积极寻找问题解决办法的心态
学历对求职的影响
点赞 评论 收藏
分享
牛客吹哨人:哨哥晚点统一更新到黑名单:能救一个是一个!26届毁意向毁约裁员黑名单https://www.nowcoder.com/discuss/1525833
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务