[IOI1998]Polygon

题意翻译

题目可能有些许修改,但大意一致

多边形是一个玩家在一个有n个顶点的多边形上的游戏,如图所示,其中n=4。每个顶点用整数标记,每个边用符号+(加)或符号*(乘积)标记。

第一步,删除其中一条边。随后每一步:

选择一条边连接的两个顶点V1和V2,用边上的运算符计算V1和V2得到的结果来替换这两个顶点。

游戏结束时,只有一个顶点,没有多余的边。

如图所示,玩家先移除编号为3的边。之后,玩家选择计算编号为1的边,然后计算编号为4的边,最后,计算编号为2的边。结果是0。

(翻译者友情提示:这里每条边的运算符旁边的数字为边的编号,不拿来计算)

编写一个程序,给定一个多边形,计算最高可能的分数。

输入格式

输入描述一个有n个顶点的多边形,它包含两行。第一行是数字n,为总边数。

第二行描述这个多边形,一共有2n个读入,每两个读入中第一个是字符,第二个是数字。

第一个字符为第一条边的计算符号(t代表相加,x代表相乘),第二个代表顶点上的数字。首尾相连。

3 < = n < = 50

对于任何一系列的操作,顶点数字都在[-32768,32767]的范围内。

输出格式

第一行,输出最高的分数。在第二行,它必须写出所有可能的被清除后的边仍能得到最高得分的列表,必须严格递增。

题目描述

Polygon is a game for one player that starts on a polygon with N vertices, like the one in Figure 1, where N=4. Each vertex is labelled with an integer and each edge is labelled with either the symbol + (addition) or the symbol * (product). The edges are numbered from 1 to N.

On the first move, one of the edges is removed. Subsequent moves involve the following steps: pick an edge E and the two vertices V1 and V2 that are linked by E; and replace them by a new vertex, labelled with the result of performing the operation indicated in E on the labels of V1 and V2. The game ends when there are no more edges, and its score is the label of the single vertex remaining.

Consider the polygon of Figure 1. The player started by removing edge 3. After that, the player picked edge 1, then edge 4, and, finally, edge 2. The score is 0.

Write a program that, given a polygon, computes the highest possible score and lists all the edges that, if removed on the first move, can lead to a game with that score.

输入输出格式

输入格式:

Your program is to read from standard input. The input describes a polygon with N vertices. It contains two lines. On the first line is the number N. The second line contains the labels of edges 1, ..., N, interleaved with the vertices' labels (first that of the vertex between edges 1 and 2, then that of the vertex between edges 2 and 3, and so on, until that of the vertex between edges N and 1), all separated by one space. An edge label is either the letter t (representing +) or the letter x (representing *).

3 <= N <= 50

For any sequence of moves, vertex labels are in the range [-32768,32767].

输出格式:

Your program is to write to standard output. On the first line your program must write the highest score one can get for the input polygon. On the second line it must write the list of all edges that, if removed on the first move, can lead to a game with that score. Edges must be written in increasing order, separated by one space.

输入输出样例

输入样例#1:

4

t -7 t 4 x 2 x 5

输出样例#1:

33

1 2

题解

  • 在做这道题目之前,相信大家之前已经做过石子合并这道题目,我们发现在枚举删掉哪条边后,就和石子合并非常相似,那我们可不可以以相似的思路来做这道题目呢?
  • 如果按照上一题的思路,我们需要定义一个dp数组,其中dp[l,r]表示从l到r内的最大值.但是这样定义状态是有误的.dp[l,r]无法从dp[l,k]+dp[k+1,r]转移而来,因为[l,k]内的最小值与[k+1,r]内的最小值可能是负数,两者相乘,结果可能比两个区间内的最大值相乘更大.
  • 那么我们想,可不可以保存一段区间内最小值和最大值两个关键值呢?答案是肯定的.因为最大值的来源只可能是两个区间内最大值相加,相乘或者是两个区间内的最小值相乘,而最小值只可能是两个区间内的最小值相加,或者是一个最大值去和另一个最小值相乘.
  • 我们定义dp[l][r][0]表示[l,r]区间内的最大值,dp[l][r][1]表示[l,r]内的最小值
  • 那么就很容易得出状态转移方程

若op为' + '

\[dp[l,r][0]=max(dp[l,r][0],dp[l,k][0]+dp[k+1,r][1])
\]

\[dp[l,r][1]=min(dp[l,r][1],dp[l,k][1]+dp[k+1,r][1])
\]

若op为' * '

\[dp[l,r][0]=max(dp[l,r][0],max(dp[l,k][0]*dp[k+1,r][0],dp[l,k][1]*dp[k+1,r][1]))
\]

\[dp[l,r][1]=min(dp[l,r][1],min(dp[l,k][0]*dp[k+1,r][1],dp[l,k][1]*dp[k+1,r][0]))
\]

  • 事实上,我们其实还可以省去枚举删除起始边的那一重循环,试想一下,无论我们从哪个地方断开边后我们都要将原数列复制一遍接在最后,形成一个2*N长的新数列,这样的话我们可以默认从1处断开,然后就是标准的区间dp\(O(n^3)\)枚举

    最后的答案就是\(max(dp[i][i+n-1][0])_{1<=i<=n}\)
#include<bits/stdc++.h>
#define MIN(a,b) (a)>(b)?(b):(a)
#define MAX(a,b) (a)>(b)?(a):(b)
#define in(i) (i=read())
using namespace std;
int read(){
int ans=0,f=1;
char i=getchar();
while(i<'0'||i>'9'){
if(i=='-') f=-1;
i=getchar();
}
while(i>='0' && i<='9'){
ans=(ans<<1)+(ans<<3)+i-'0';
i=getchar();
}
return ans*f;
}
const int inf=20000000;
int n,cnt;
int dp[150][150][2];
int a[110];
char op[110];
inline void init(){
for(int i=1;i<=2*n;i++){
for(int j=i;j<=2*n;j++){
dp[i][j][0]=-inf,dp[i][j][1]=inf;
}
}
for(int i=1;i<=n;i++){
dp[i][i][0]=dp[i][i][1]=dp[i+n][i+n][0]=dp[i+n][i+n][1]=a[i];
}
}
void dp1(int l,int r,int k){
dp[l][r][0]=MAX(dp[l][r][0],dp[l][k][0]+dp[k+1][r][0]);
dp[l][r][1]=MIN(dp[l][r][1],dp[l][k][1]+dp[k+1][r][1]);
}
void dp2(int l,int r,int k){
dp[l][r][0]=MAX(dp[l][r][0],MAX(dp[l][k][0]*dp[k+1][r][0],dp[l][k][1]*dp[k+1][r][1]));
dp[l][r][1]=MIN(dp[l][r][1],MIN(dp[l][k][0]*dp[k+1][r][1],dp[l][k][1]*dp[k+1][r][0]));
}
int main()
{
int ans=-inf;
in(n);
for(int i=1;i<=n;i++){
cin>>op[i];in(a[i]);
op[i+n]=op[i];a[i+n]=a[i];
}
init();
for(int len=2;len<=n;len++){
for(int l=1;l<=2*n;l++){
int r=l+len-1;
for(int k=l;k<r;k++){
if(op[k+1]=='t') dp1(l,r,k);
else dp2(l,r,k);
}
}
}
for(int i=1;i<=n;i++) ans=MAX(ans,dp[i][i+n-1][0]);
cout<<ans<<endl;
for(int i=1;i<=n;i++){
if(dp[i][i+n-1][0]==ans) cout<<i<<" ";
}
cout<<endl;
return 0;
}

IOI1998 Polygon [区间dp]的更多相关文章

  1. [IOI1998] Polygon (区间dp,和石子合并很相似)

    题意: 给你一个多边形(可以看作n个顶点,n-1条边的图),每一条边上有一个符号(+号或者*号),这个多边形有n个顶点,每一个顶点有一个值 最初你可以把一条边删除掉,这个时候这就是一个n个顶点,n-2 ...

  2. 【IOI1998】Polygon 区间DP

    题意翻译 题目可能有些许修改,但大意一致 多边形是一个玩家在一个有n个顶点的多边形上的游戏,如图所示,其中n=4.每个顶点用整数标记,每个边用符号+(加)或符号*(乘积)标记. 第一步,删除其中一条边 ...

  3. POJ 1179 - Polygon - [区间DP]

    题目链接:http://poj.org/problem?id=1179 Time Limit: 1000MS Memory Limit: 10000K Description Polygon is a ...

  4. IOI 98 (POJ 1179)Polygon(区间DP)

    很容易想到枚举第一步切掉的边,然后再计算能够产生的最大值. 联想到区间DP,令dp[i][l][r]为第一步切掉第i条边后从第i个顶点起区间[l,r]能够生成的最大值是多少. 但是状态不好转移,因为操 ...

  5. 【POJ1179】Polygon 区间DP

    这道题是典型的环形石子归并模型,破环成链后时间复杂度为\(O(n^3)\) 不过,因为题目中所给的数字可能是负数,仅仅记录区间内合并之后的最大值并不满足动态规划的最优子结构性质.因此,还需要额外记录下 ...

  6. POJ1179 Polygon 区间DP

    题目大意: 多边形游戏,有N个顶点的多边形,3 <= N <= 50 ,多边形有N条边,每个顶点中有一个数字(可正可负),每条边上或者是“+”号,或者是“*”号.边从1到N编号,首先选择一 ...

  7. 【洛谷 P4342】[IOI1998]Polygon(DP)

    题目链接 题意不再赘述. 这题和合并石子很类似,但是多了个乘法,而乘法是不满足"大大得大"的,因为两个非常小的负数乘起来也会很大,一个负数乘一个很大的整数会很小,所以我们需要添加一 ...

  8. 「IOI1998」「LuoguP4342」Polygon(区间dp

    P4342 [IOI1998]Polygon - 洛谷 题意翻译 题目可能有些许修改,但大意一致 多边形是一个玩家在一个有n个顶点的多边形上的游戏,如图所示,其中n=4.每个顶点用整数标记,每个边用符 ...

  9. [IOI1998]Polygon(区间dp)

    [IOI1998]Polygon 题意翻译 多边形是一个玩家在一个有n个顶点的多边形上的游戏,如图所示,其中n=4.每个顶点用整数标记,每个边用符号+(加)或符号*(乘积)标记. 第一步,删除其中一条 ...

随机推荐

  1. 基于pygame的打砖块游戏,做到一半,不带做了

    跟着一个博主做的,前面的变量的定义全是内个哥们的,没带任何改动,就做了个界面,背景音乐,绘制了个小球,绘制了挡板 小球可以撞到边界反弹,然后做了砖块,定义了一个存放砖块的列表,,,就没有下文了 原博主 ...

  2. web学习第一天

    学习web心得 表格 table,表单 form,跑马灯效果 marquee,导入背景图片<img src="图片路径"> 第一天学的不是很难,作业也相对来说比较简单, ...

  3. python中 列表常用的操作

    列表可以装大量的数据,不限制数据类型,表示方式:[]:列表中的元素用逗号隔开. lst = [] #定义一个空列表 lst = ["Tanxu",18,"女", ...

  4. python系列7进程线程和协程

    目录 进程 线程 协程  上下文切换 前言:线程和进程的关系图 由下图可知,在每个应用程序执行的过程中,都会去产生一个主进程和主线程来完成工作,当我们需要并发的执行的时候,就会通过主进程去生成一系列的 ...

  5. 【Python让生活更美好01】os与shutil模块的常用方法总结

    Python作为一种解释型的高级语言,脚本语言,又被称作“胶水语言”,就是因为其灵活的语法和其依靠浩如烟海的第三方包实现的丰富多彩的功能,而os和shutil就是这样一种功能强大的模块,可以非常快捷地 ...

  6. R语言学习笔记(二): 类与泛型函数

    类 大多数R对象都是基于S3类(来源于第三代S语言),例如直方图函数hist()输出是一个包含多个组件的列表,它还有一个属性(attribute),用来指定列表的类,即histogram类. 泛型函数 ...

  7. 洛谷P4016 负载平衡问题

    题目描述 G 公司有 n 个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量不等.如何用最少搬运量可以使 n 个仓库的库存数量相同.搬运货物时,只能在相邻的仓库之间搬运. 输入输出格式 输入格式: ...

  8. WPF中使用第三方字体选择器

    原文:WPF中使用第三方字体选择器 起因 到WPF的字体可以设置的东西变得非常的多,而却没有提供专用的字体选择对话框,甚至于WinFrom的FontDialog也是不能直接用来设置WPF中的字体.解决 ...

  9. php复制目录很浪

    一不小心搞出个超级深层次文件夹 主要是因为懒,在网上随便找了段复制文件夹的代码贴上了,结果是很恐怖,一个文件夹复制到他自身里面的时候,将会产生循环嵌套文件夹,后果是,windows因为文件名太长而无法 ...

  10. 转载:Linux系统和Linux系统之间如何实现文件传输

    两台Linux系统之间传输文件 听语音 | 浏览:13183 | 更新:2014-07-15 15:22 | 标签:linux 1 2 3 4 5 6 分步阅读 如何在Linux系统之间传输文件及文件 ...