题意:有一个n个点的简单环。环上每个节点有一个数字,每个节点间的连边上有一个字符'x'或者't',在游戏开始前先删除一条边,然后每次选择一条边删除,若这条边上字符为't'则边的两个节点相加并生成为一个新的节点,'x'的话则相乘,直到只剩下一个节点为止,问剩下的这个节点最大是多少,且先删除哪一条边可以得到这个最大值。
思路:区间dp,每次选择一条边删除,那么我们可以把这些节点放在一个数组a里,然后a[i+n]=a[i],复制一遍该数组,然后枚举区间的起点,i为起点时则是先删除了第i条边。
ps:由于此题运算过程存在负数且有乘法,则可能出现某个区间最大的结果=两个值为负数的子区间相乘,所以我们要再设一个数组用来存区间的最小值。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define PI acos(-1)
#define INF 0x3f3f3f3f
#define NUM 2000005
#define debug false
#define ll long long
#define lowbit(x) ((-x)&x)
#define ffor(i,d,u) for(int i=d;i<=u;++i)
#define _ffor(i,u,d) for(int i=u;i>=d;--i)
#define mst(array,Num) memset(array,Num,sizeof(array))
const int P = 1e9+7;
int n;
int ans[51],maxnum=-INF;
char c;
int dp[102][102],link[102][102],dp2[102][102];//dp存最大值,dp2存最小值,link为两个点的边
template <typename T>
void read(T& x)
{
x=0;
char c;T t=1;
while(((c=getchar())<'0'||c>'9')&&c!='-');
if(c=='-'){t=-1;c=getchar();}
do(x*=10)+=(c-'0');while((c=getchar())>='0'&&c<='9');
x*=t;
}
template <typename T>
void write(T x)
{
int len=0;char c[21];
if(x<0)putchar('-'),x*=(-1);
do{++len;c[len]=(x%10)+'0';}while(x/=10);
_ffor(i,len,1)putchar(c[i]);
}
void AC()
{
int j,i,k,z,n1;
scanf("%d",&n);
j=0;
getchar();
c=getchar();
if(c=='t')link[n][n+1]=0;
else link[n][n+1]=1;
scanf("%d",&dp[1][1]);
dp2[1][1]=dp2[1+n][1+n]=dp[1+n][1+n]=dp[1][1];
ffor(i,2,n)
{
getchar();
c=getchar();
if(c=='t')link[i+n-1][i+n]=link[i-1][i]=0;
else link[i+n-1][i+n]=link[i-1][i]=1;
scanf("%d",&dp[i][i]);
dp2[i+n][i+n]=dp2[i][i]=dp[i+n][i+n]=dp[i][i];
}
for(i=1;i<=n;++i)
{
n1=i+n-1;
for(j=i;j<=n1;++j)for(k=j+1;k<=n1;++k)dp[j][k]=-INF,dp2[j][k]=INF;
for(j=1;j<n;++j)
for(k=i;k<=n1-j;++k)
for(z=k;z<k+j;++z)
if(link[z][z+1]==1)
{
dp[k][k+j]=max(dp[k][k+j],dp[k][z]*dp[z+1][k+j]);
dp[k][k+j]=max(dp[k][k+j],dp2[k][z]*dp2[z+1][k+j]);
dp[k][k+j]=max(dp[k][k+j],dp[k][z]*dp2[z+1][k+j]);
dp[k][k+j]=max(dp[k][k+j],dp2[k][z]*dp[z+1][k+j]);
dp2[k][k+j]=min(dp2[k][k+j],dp2[k][z]*dp[z+1][k+j]);
dp2[k][k+j]=min(dp2[k][k+j],dp[k][z]*dp[z+1][k+j]);
dp2[k][k+j]=min(dp2[k][k+j],dp[k][z]*dp2[z+1][k+j]);
dp2[k][k+j]=min(dp2[k][k+j],dp2[k][z]*dp2[z+1][k+j]);
}
else
{
dp[k][k+j]=max(dp[k][k+j],dp[k][z]+dp[z+1][k+j]);
dp2[k][k+j]=min(dp2[k][k+j],dp2[k][z]+dp2[z+1][k+j]);
}
ans[i]=dp[i][n1];
maxnum=max(maxnum,ans[i]);
}
printf("%d\n",maxnum);
for(i=1;i<n;++i)if(ans[i]==maxnum)printf("%d ",i);
if(ans[n]==maxnum)printf("%d",n);
}
int main()
{
AC();
return 0;
}