题解 P4342 【[IOI1998]Polygon】
luogu
此题是道区间dp,理论上可做
不会区间dp板子的就算了
此题基本思路参照石子合并
但是,此题有加有乘(没有人不知道吧),若只有加则基本是合并石子
而乘就稍微恶心,有个神奇的初一知识点:
负负得正
所以,本题不再是一个DP数组,而是两个!
dpmax[i][j]=max(dpmax[i][j],max(dpmax[i][k]*dpmax[k+1][j],dpmin[i][k]*dpmin[k+1][j]));//最大值考虑负负得正
dpmin[i][j]=min(dpmin[i][j],min(min(dpmax[i][k]*dpmin[k+1][j],dpmin[i][k]*dpmax[k+1][j]),dpmin[i][k]*dpmin[k+1][j]));//最小值分类讨论
至于破哪条边。。。区间dp时不就默认破成链了吗?
上代码(有注释)
#include<bits/stdc++.h>
using namespace std;
int n,num[110],dpmax[110][110],dpmin[110][110],ans=-999999999;
/*dpmax[i][j]表示i到j的最大值,dpmin[i][j]表示其最小值*/
char fh[110];
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>fh[i]>>num[i];
fh[i+n]=fh[i];
num[i+n]=num[i];//破环为链
}
for(int i=1;i<=2*n;i++)
{
for(int j=1;j<=2*n;j++)
{
if(i==j)
{
dpmax[i][j]=num[i];
dpmin[i][j]=num[i];//没有不理解初始化的吧
}
else
{
dpmax[i][j]=-20000;
dpmin[i][j]=20000;
}
}
}
for(int l=2;l<=n;l++)
{
for(int i=1;i+l-1<=2*n;i++)
{
int j=i+l-1;
for(int k=i;k<j;k++)//区间dp板子
{
if(fh[k+1]=='x')
{
dpmax[i][j]=max(dpmax[i][j],max(dpmax[i][k]*dpmax[k+1][j],dpmin[i][k]*dpmin[k+1][j]));//最大值考虑负负得正
dpmin[i][j]=min(dpmin[i][j],min(min(dpmax[i][k]*dpmin[k+1][j],dpmin[i][k]*dpmax[k+1][j]),dpmin[i][k]*dpmin[k+1][j]));//最小值分类讨论
}
else
{
dpmax[i][j]=max(dpmax[i][j],dpmax[i][k]+dpmax[k+1][j]);
dpmin[i][j]=min(dpmin[i][j],dpmin[i][k]+dpmin[k+1][j]);
}
}
}
}
for(int i=1;i<=n;i++)
{
ans=max(ans,dpmax[i][i+n-1]);
}
cout<<ans<<endl;
for(int i=1;i<=n;i++)
{
if(dpmax[i][i+n-1]==ans)//前文说过,区间dp已默认破了边
{
cout<<i<<" ";
}
}
}