题解 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<<" ";
		}
	}
}
posted @ 2019-01-28 19:56  G_A_TS  阅读(469)  评论(4编辑  收藏  举报