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

第一步,删除其中一条边。随后每一步:
选择一条边连接的两个顶点V1和V2,用边上的运算符计算V1和V2得到的结果来替换这两个顶点。
游戏结束时,只有一个顶点,没有多余的边。
如图所示,玩家先移除编号为3的边。之后,玩家选择计算编号为1的边,然后计算编号为4的边,最后,计算编号为2的边。结果是0。

(翻译者友情提示:这里每条边的运算符旁边的数字为边的编号,不拿来计算)
编写一个程序,给定一个多边形,计算最高可能的分数。
输入格式
输入描述一个有n个顶点的多边形,它包含两行。第一行是数字n,为总边数。
第二行描述这个多边形,一共有2n个读入,每两个读入中第一个是字符,第二个是数字。
第一个字符为第一条边的计算符号(t代表相加,x代表相乘),第二个代表顶点上的数字。首尾相连。
3 < = n < = 50
对于任何一系列的操作,顶点数字都在[-32768,32767]的范围内。
输出格式
第一行,输出最高的分数。在第二行,它必须写出所有可能的被清除后的边仍能得到最高得分的列表,必须严格递增。
一道区间dp很好的题目,很容易想到这样定义状态:\(F[i][j]\)表示把顶点\(i\)到\(j\)合并起来所获得的最大得分。但是发现顶点数据的范围可以为负数,而最大值可能由两个负数乘得(很容易忽略的点,做题要考虑周全),所以我们需要同时记录最大值和最小值。由此\(F[i][j][0]\)表示把顶点\(i\)到\(j\)合并起来所获得的最小得分,\(F[i][j][1]\)表示把顶点\(i\)到\(j\)合并起来所获得的最大得分。
然后也许会想到直接去枚举断掉哪条边,但我们可以优化一下,像处理环状一样把链复制一遍到后面,因为每次断掉边之后就变成了链,所以我们可以一次处理出断掉每条边的值。
注意初始化
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
int read()
{
int x=0,w=1;char ch=getchar();
while(ch>'9'||ch<'0') {if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*w;
}
int n;
int c[1100],a[1100],team[1100];
int f[310][310][2];
void work1(int i,int j,int k)
{
f[i][j][1]=max(f[i][j][1],f[i][k][1]+f[k+1][j][1]);
f[i][j][0]=min(f[i][j][0],f[i][k][0]+f[k+1][j][0]);
}
void work2(int i,int j,int k)
{
f[i][j][1]=max(f[i][j][1],max(f[i][k][1]*f[k+1][j][1],f[i][k][0]*f[k+1][j][0]));
f[i][j][0]=min(f[i][j][0],min(min(f[i][k][0]*f[k+1][j][0],f[i][k][1]*f[k+1][j][0]),f[i][k][0]*f[k+1][j][1]));
}
void init()
{
for(int i=1;i<=2*n;i++)
{
for(int j=i;j<=2*n;j++)
f[i][j][1]=-20000000,f[i][j][0]=20000000;
}
for(int i=1;i<=n;i++)
{
f[i][i][1]=f[i][i][0]=a[i];
f[i+n][i+n][1]=f[i+n][i+n][0]=a[i];
}
}
int main()
{
char ch;
int cnt=0,ans=-20000000;
n=read();
for(int i=1;i<=n;i++)
{
cin>>ch;
if(ch=='t') c[i]=1;
if(ch=='x') c[i]=2;
a[i]=read();
a[i+n]=a[i];c[i+n]=c[i];
}
init();
for(int l=2;l<=n;l++)
{
for(int i=1;i<=2*n;i++)
{
int j=i+l-1;
for(int k=i;k<j;k++)
{
if(c[k+1]==1) work1(i,j,k);
else work2(i,j,k);
}
}
}
for(int i=1;i<=n;i++)
{
if(f[i][i+n-1][1]>ans)
{
ans=f[i][i+n-1][1];
cnt=0;
team[++cnt]=i;
}
else if(f[i][i+n-1][1]==ans) team[++cnt]=i;
}
cout<<ans<<endl;
for(int i=1;i<=cnt;i++)
{
cout<<team[i]<<" ";
}
}
[IOI1998]Polygon(区间dp)的更多相关文章
- IOI1998 Polygon [区间dp]
[IOI1998]Polygon 题意翻译 题目可能有些许修改,但大意一致 多边形是一个玩家在一个有n个顶点的多边形上的游戏,如图所示,其中n=4.每个顶点用整数标记,每个边用符号+(加)或符号*(乘 ...
- [IOI1998] Polygon (区间dp,和石子合并很相似)
题意: 给你一个多边形(可以看作n个顶点,n-1条边的图),每一条边上有一个符号(+号或者*号),这个多边形有n个顶点,每一个顶点有一个值 最初你可以把一条边删除掉,这个时候这就是一个n个顶点,n-2 ...
- 【IOI1998】Polygon 区间DP
题意翻译 题目可能有些许修改,但大意一致 多边形是一个玩家在一个有n个顶点的多边形上的游戏,如图所示,其中n=4.每个顶点用整数标记,每个边用符号+(加)或符号*(乘积)标记. 第一步,删除其中一条边 ...
- POJ 1179 - Polygon - [区间DP]
题目链接:http://poj.org/problem?id=1179 Time Limit: 1000MS Memory Limit: 10000K Description Polygon is a ...
- IOI 98 (POJ 1179)Polygon(区间DP)
很容易想到枚举第一步切掉的边,然后再计算能够产生的最大值. 联想到区间DP,令dp[i][l][r]为第一步切掉第i条边后从第i个顶点起区间[l,r]能够生成的最大值是多少. 但是状态不好转移,因为操 ...
- 【POJ1179】Polygon 区间DP
这道题是典型的环形石子归并模型,破环成链后时间复杂度为\(O(n^3)\) 不过,因为题目中所给的数字可能是负数,仅仅记录区间内合并之后的最大值并不满足动态规划的最优子结构性质.因此,还需要额外记录下 ...
- POJ1179 Polygon 区间DP
题目大意: 多边形游戏,有N个顶点的多边形,3 <= N <= 50 ,多边形有N条边,每个顶点中有一个数字(可正可负),每条边上或者是“+”号,或者是“*”号.边从1到N编号,首先选择一 ...
- 【洛谷 P4342】[IOI1998]Polygon(DP)
题目链接 题意不再赘述. 这题和合并石子很类似,但是多了个乘法,而乘法是不满足"大大得大"的,因为两个非常小的负数乘起来也会很大,一个负数乘一个很大的整数会很小,所以我们需要添加一 ...
- 「IOI1998」「LuoguP4342」Polygon(区间dp
P4342 [IOI1998]Polygon - 洛谷 题意翻译 题目可能有些许修改,但大意一致 多边形是一个玩家在一个有n个顶点的多边形上的游戏,如图所示,其中n=4.每个顶点用整数标记,每个边用符 ...
随机推荐
- Jenkins 使用python进行调度,并下载apphost上的安装包
在持续集成的过程中,Jenkins工具是我们必须要会用的工具,那么今天分享一个使用python对Jenkins进行调度的案例 使用的是python-jenkins 库,借用selenium登陆jenk ...
- django 使用ORM插入数据,提示Cannot assign "1": "B" must be a "Projectconfig" instance.
这是因为使用了外键导致的, 如果使用了外键,先实例化外键查询,然后再插入的表里面放入实例化后的外键连接
- 030:spaceless和autoescape 标签
1.spaceless 标签: spaceless 标签:移除html标签中的空白字符.包括空格.tab键.换行等.示例代码如下: {% spaceless %} <p> <a hr ...
- Map.Entry的由来和使用
首先,回忆和练习一下HashMap的遍历 package Exercise.exercise; import java.util.HashMap; import java.util.Iterator; ...
- Python_014(面向对象之继承)
一.面向对象之继承 1.初始继承 引入:面向对象的三大特性:继承,多态,封装 a.继承是创建新类的一种方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类;新建的类称为派生类 ...
- Node对象的一些方法
Node对象是什么提供了 DOM的标准规范提供了Node对象,该对象主要提供了解析DOM节点树结构的属性和方法,DOM树结构主要是依靠节点进行解析,称为DOM节点树结构.Node对象是解析DOM节点树 ...
- 2019牛客暑期多校训练营(第六场)C - Palindrome Mouse (回文自动机)
https://ac.nowcoder.com/acm/contest/886/C 题意: 给出一个串A , 集合S里面为A串的回文字串 , 现在在集合S里面找出多少对(a,b),b为a的字串 分析: ...
- elasticsearch 集群搭建及启动常见错误
1.系统环境 三台服务器(最好是单数台,跟master选举方式有关),确保机器互相ping的通,且都需要装了jdk 8环境,机器IP和 elasticsearch 的节点名称如下: cluster n ...
- day13—CSS之导航栏
转行学开发,代码100天——2018-03-29 见过这么多网页,没有导航栏的几乎没见过.因此,对导航栏的练习非常之必要. 导航栏的实现,基本上都是通过链接列表实现,即ul->li->a标 ...
- C++ 编写的DLL导出的函数名乱码含义解析
C++编译时函数名修饰约定规则: __stdcall调用约定: 1.以"?"标识函数名的开始,后跟函数名: 2.函数名后面以"@@YG"标识参数表的 ...