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;
}
posted @ 2020-04-22 16:06  With_penguin  阅读(86)  评论(0编辑  收藏  举报