poj挂了快两天了。。
洛谷的今日运势真的强,说能完成WA的题就能完成。。
咳咳,区间DP。
思路类似合并果子,不过在维护f[i][j] (i到j的最大值) 同时也要维护g[i][j] (i到j的最小值)
为什么呢?考虑把区间劈成左右两个的一次转移:
对于加法:
1.最大值显然是左右的最大值之和 max+max
对于乘法:
1.最大值是左右区间最大值的乘积 max*max
2.以及最小值的乘积(负数情况) min*min
因此要同时维护一下最小值才行,具体做法:
对于加法:
1.最小值是左右最小值之和
对于乘法:
1.左右最小值的乘积
2.左最小值*右最大值
3.左最大值*右最小值
对于环的处理:断开,复制一倍
手c数组真的很危险。。WA的原因是只初始化[0,n]的数组,[n+1,n*2]的没管。
emacs默认的两格缩进自己看还行,好像发上来效果很挤?
#include<iostream>
#include<cstdio>
using namespace std;
const int MAXN=500;
const int INF=1<<30;
int n;
char op[MAXN];
int f[MAXN][MAXN],g[MAXN][MAXN];
int main(){
scanf("%d",&n);
for(int i=0;i<=2*n;i++){//2*
for(int j=0;j<=2*n;j++){//2*
f[i][j]=-INF;
g[i][j]=INF;
}
}
for(int i=1;i<=n;i++){
char s[5];
scanf("%s%d",s,&f[i][i]);
// cin>>op[i-1]>>f[i][i];
g[i][i]=f[i][i];
g[i+n][i+n]=f[i+n][i+n]=f[i][i];
op[i+n-1]=op[i-1]=s[0];
}
op[n<<1]=op[0];
for(int len=1;len<=n;len++){
for(int i=1;i+len<=2*n;i++){//2*
int j=i+len;
for(int k=i;k<j;k++){
if(op[k]=='t'){
f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]);
g[i][j]=min(g[i][j],g[i][k]+g[k+1][j]);
}else{
f[i][j]=max(f[i][j],max(f[i][k]*f[k+1][j],g[i][k]*g[k+1][j]));
g[i][j]=min(g[i][j],min(g[i][k]*g[k+1][j],min(g[i][k]*f[k+1][j],f[i][k]*g[k+1][j])));
}
}
}
}
int mx=-INF;
for(int i=1;i<=n;i++)mx=max(mx,f[i][i+n-1]);
cout<<mx<<endl;
for(int i=1;i<=n;i++){
if(f[i][i+n-1]==mx)cout<<i<<" ";
}
return 0;
}