luogu P4342 [IOI1998]Polygon
这是一道区间DP(几乎是裸题)。
看到环首先断环为链,然后发现只有两个数相乘负负得正的情况不好处理,所以在此记录\(f[i][j]\)表示区间\(i-j\)的最大值,\(g[i][j]\)表示区间\(i-j\)的最小值,由于分正负号讨论非常的麻烦,而答案只可能在\((f[i][k-1]*f[k][j],f[i][k-1]*g[k][j],g[i][k-1]*f[k][j],g[i][k-1]*g[k][j])\)这些值中产生,不妨直接取最大(小)值转移就行了。
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=200,INF=1<<30;
int a[N],f[N][N],g[N][N],n;
char b[N];
int read()
{
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9')
{
if(c=='-')
f=-1;
c=getchar();
}
while(c>='0'&&c<='9')
x=x*10+c-'0',c=getchar();
return x*f;
}
void init()
{
scanf("%d\n",&n);
for (int i=1;i<=n;i++)
{
scanf("%c",&b[i]);
a[i]=read();
a[i+n]=a[i],b[i+n]=b[i];
}
}
void work()
{
for (int i=1;i<=n<<1;i++)
f[i][i]=g[i][i]=a[i];
for (int l=2;l<=n;l++)
for (int i=1;i+l-1<=n<<1;i++)
{
int j=i+l-1;
g[i][j]=INF,f[i][j]=-INF;
for (int k=i+1;k<=j;k++)
if(b[k]=='t')
{
f[i][j]=max(f[i][j],f[i][k-1]+f[k][j]);
g[i][j]=min(g[i][j],g[i][k-1]+g[k][j]);
}
else
{
f[i][j]=max(f[i][j],max(f[i][k-1]*f[k][j],max(f[i][k-1]*g[k][j],max(g[i][k-1]*f[k][j],g[i][k-1]*g[k][j]))));
g[i][j]=min(g[i][j],min(f[i][k-1]*f[k][j],min(f[i][k-1]*g[k][j],min(g[i][k-1]*f[k][j],g[i][k-1]*g[k][j]))));
}
}
int ans=-INF;
for (int i=1;i<=n;i++)
ans=max(ans,f[i][i+n-1]);
printf("%d\n",ans);
for (int i=1;i<=n;i++)
if(ans==f[i][i+n-1])
printf("%d ",i);puts("");
}
int main()
{
init();
work();
return 0;
}
由于博主比较菜,所以有很多东西待学习,大部分文章会持续更新,另外如果有出错或者不周之处,欢迎大家在评论中指出!