[IOI1998]Polygon
这都是RLD
二十年前就AK
的题了
我今天才来写
题目都要求先断一条边了
就直接倍长,在链上算
显然是一个区间dp
加法可以枚举中间点直接转移
但是因为有负数,乘法转移时不一定有最大值转移来
所以同时转移最小值
#include<cstdio>
#include<iostream>
using namespace std;
#define gc c=getchar()
#define r(x) read(x)
template<typename T>
inline void read(T&x){
x=0;T k=1;char gc;
while(!isdigit(c)){if(c=='-')k=-1;gc;}
while(isdigit(c)){x=x*10+c-'0';gc;}x*=k;
}
const int INF=32768;
const int N=105;
inline char GetChar(){
char gc;
while(c!='t'&&c!='x')gc;
return c;
}
int a[N],mx[N][N],mi[N][N];
char op[N];
int main(){
int n;r(n);
for(int i=1;i<=n;++i){
op[i]=GetChar(),r(a[i]);
op[i+n]=op[i],a[i+n]=a[i];
}
n<<=1;
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j){
mx[i][j]=-INF;
mi[i][j]=INF;
}
}
for(int i=1;i<=n;++i)mx[i][i]=mi[i][i]=a[i];
for(int len=2;len<=n;++len){
for(int l=1,r=len;r<=n;++l,++r){
for(int i=l;i<r;++i){
if(op[i+1]=='t'){
mx[l][r]=max(mx[l][r],mx[l][i]+mx[i+1][r]);
mi[l][r]=min(mi[l][r],mi[l][i]+mi[i+1][r]);
}
else {
mx[l][r]=max(mx[l][r],mx[l][i]*mx[i+1][r]);
mx[l][r]=max(mx[l][r],mi[l][i]*mi[i+1][r]);
mi[l][r]=min(mi[l][r],mi[l][i]*mi[i+1][r]);
mi[l][r]=min(mi[l][r],mx[l][i]*mi[i+1][r]);
mi[l][r]=min(mi[l][r],mi[l][i]*mx[i+1][r]);
}
}
}
}
n>>=1;
int ans=-INF;
for(int i=1;i<=n;++i){
ans=max(ans,mx[i][i+n-1]);
}
printf("%d\n",ans);
for(int i=1;i<=n;++i){
if(mx[i][i+n-1]==ans){
printf("%d ",i);
}
}
}