首页 > 其他分享 >环形石子合并

环形石子合并

时间:2022-09-02 21:00:11浏览次数:81  
标签:得分 int 石子 合并 环形 区间 长度

环形石子合并

将 $n$ 堆石子绕圆形操场排放,现要将石子有序地合并成一堆。

规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数记做该次合并的得分。

请编写一个程序,读入堆数 $n$ 及每堆的石子数,并进行如下计算:

  • 选择一种合并石子的方案,使得做 $n−1$ 次合并得分总和最大。
  • 选择一种合并石子的方案,使得做 $n−1$ 次合并得分总和最小。

输入格式

第一行包含整数 $n$,表示共有 $n$ 堆石子。

第二行包含 $n$ 个整数,分别表示每堆石子的数量。

输出格式

输出共两行:

第一行为合并得分总和最小值,

第二行为合并得分总和最大值。

数据范围

$1\leq n \leq 200$

输入样例:

4
4 5 9 4

输出样例:

43
54

 

解题思路

  这题与石子合并差不多一样,只是这题变成了环,需要破环成链。

  比如说有$4$堆石子,那么除了将 1 2 3 4 合并成一堆石子这种合并方式外,还可以是 2 3 4 1 , 3 4 1 2 , 4 1 2 3 。为了能把环变成区间来求解,就需要破环成链。一个朴素的想法是枚举每一个缺口(因为有$n$堆石子,因此需要合并$n-1$次,每次合并意味着在两个不连通的点之间连一条线,$n$个点最后有$n-1$条边,因此存在一个缺口,拉开就成一条链了),此时就得到一个区间,可以做区间dp。但这种做法的时间复杂度为$O(n^4)$。

  一共有$n$种缺口,意味着有$n$种不同的链。问题的本质是求$n$个长度为$n$的链的区间dp。因此可以在长度为$n$的区间的后面再接一个长度为$n$的区间,这样区间的长度就变成的$2n$,$n$个长度为$n$的链都在这个长度为$2n$的区间上。

  因此可以在这个长度为$2n$的链上做区间dp,时间复杂度就变成$O(n^3)$。

  AC代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 410;
 5 
 6 int s[N];
 7 int f[N][N], g[N][N];
 8 
 9 int main() {
10     int n;
11     scanf("%d", &n);
12     for (int i = 1; i <= n; i++) {
13         scanf("%d", s + i);
14         s[i + n] = s[i];    // 扩展为2倍的长度
15     }
16     for (int i = 1; i <= n << 1; i++) {
17         s[i] += s[i - 1];   // 求前缀和
18     }
19     
20     memset(f, 0x3f, sizeof(f));
21     memset(g, -0x3f, sizeof(g));
22     for (int len = 1; len <= n; len++) {
23         for (int i = 1; i + len - 1 <= n << 1; i++) {
24             int j = i + len - 1;
25             if (len == 1) {
26                 f[i][j] = g[i][j] = 0;
27             }
28             else {
29                 for (int k = i; k < j; k++) {
30                     f[i][j] = min(f[i][j], f[i][k] + f[k + 1][j] + s[j] - s[i - 1]);
31                     g[i][j] = max(g[i][j], g[i][k] + g[k + 1][j] + s[j] - s[i - 1]);
32                 }
33             }
34         }
35     }
36     
37     int minv = 2e9, maxv = -2e9;
38     for (int i = 1; i <= n; i++) {  // 枚举所有长度为n的区间,一共有n个
39         minv = min(minv, f[i][i + n - 1]);
40         maxv = max(maxv, g[i][i + n - 1]);
41     }
42     printf("%d\n%d", minv, maxv);
43     
44     return 0;
45 }

 

参考资料

  AcWing 1068. 环形石子合并(算法提高课):https://www.acwing.com/video/407/

标签:得分,int,石子,合并,环形,区间,长度
From: https://www.cnblogs.com/onlyblues/p/16651202.html

相关文章

  • 220902_leetcode 21. Merge Two Sorted Lists 合并两个有序链表(简单).md
    一、题目大意将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。示例1:输入:l1=[1,2,4],l2=[1,3,4]输出:[1,1,2,......
  • leetCode - 88 合并两个有序数组
    leetCode-88合并两个有序数组题目给你两个按非递减顺序排列的整数数组 nums1和nums2,另有两个整数m和n,分别表示nums1和nums2中的元素数目。请你合并n......
  • 题02-线性结构1 两个有序链表序列的合并(代码和笔记)
    @目录题目思路补充的代码题目本题要求实现一个函数,将两个链表表示的递增整数序列合并为一个非递减的整数序列。函数接口定义:ListMerge(ListL1,ListL2);其中Li......
  • 浅淡线段树合并
    线段树,是信息学比赛中一种强有力的数据结构;动态开点,让线段树在数据范围上挣脱了束缚;线段树合并,让树上问题获得了升华。前言线段树合并的基础——动态开点线段树在初学......
  • 在 Python 中将具有不同标题的多个 CSV 文件合并到一个文件中
    在Python中将具有不同标题的多个CSV文件合并到一个文件中在使用CSV文件进行数据分析时,我们可能需要处理大型数据集。在这些情况下,我们必须将所有数据合并到一个CS......
  • 石子合并
    石子合并设有$N$堆石子排成一排,其编号为$1,2,3,\dots,N$。每堆石子有一定的质量,可以用一个整数来描述,现在要将这$N$堆石子合并成为一堆。每次只能合并相邻的两堆......
  • 合并k个有序列表-python
    主要思路:借鉴堆、队列特点,构建新的有序结果#mergetheksortedlist#mainidea:将每个list放入队列,初始一个小顶堆,size为list个数,value为队列的首个元素,交替寻找最......
  • GroupBy中多列合并一列方法
    varquery=list.GroupBy(t=>new{t....分组字段}).Select(g=>new{FROM=g.Key.From,TO=g.Key.To,NUM=g.Count(),Time=g.Key.Time,Body=string.Join(",",g.Select(s=>......
  • 使用 Apollo Server 和 Koa 合并 GraphQL Schema
    使用ApolloServer和Koa合并GraphQLSchema今天,在我们现代的开发者世界中,完全无法想象没有React、NodeJS、GraphQL等技术的生活。他们拥有稳固的队伍,并在数据交......
  • vue.js3: 多张图片合并([email protected])
    一,安装用到的第三方库1,安装:liuhongdi@lhdpc:/data/vue/pdf/image2pdf$npmi-Svuedraggable@nextadded2packagesin11s2,查看已安装的版本:liuhongdi@lhd......