【IOI1998】Polygon(区间dp)

设f(l,r,0)表示区间[l,r]操作后的最大值,f(l,r,1)表示区间[l,r]操作后的最小值,简单的区间合并即可。

可以把第一条边断掉,然后把这后面的N个点复制一遍,直接做N*2长度的区间dp。

答案是max:f(i,i+N-1,0)。

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;

int N;
int f[105][105][2];
int val[105];
char op[105];

int main(){
//	freopen("in.txt","r",stdin);
	cin>>N;
	cin>>op[N]>>val[1];
	for(int i=2;i<N;i++)
		cin>>op[i-1]>>val[i];
	cin>>op[N-1]>>val[N];
	for(int i=N+1;i<=N*2;i++)
		op[i]=op[i-N],val[i]=val[i-N];
	for(int i=1;i<=N*2;i++)
		f[i][i][0]=f[i][i][1]=val[i];
	for(int len=2;len<=N;len++)
	for(int i=1;i+len-1<=N*2;i++){
		int j=i+len-1,MAX=-INF,MIN=INF;
		for(int k=i;k+1<=j;k++){
			if(op[k]=='t'){
				MAX=max(MAX,f[i][k][0]+f[k+1][j][0]);
				MIN=min(MIN,f[i][k][1]+f[k+1][j][1]);
			}
			else{
				MAX=max(MAX,f[i][k][0]*f[k+1][j][0]);
				MIN=min(MIN,f[i][k][0]*f[k+1][j][1]);
				MIN=min(MIN,f[i][k][1]*f[k+1][j][0]);
				MAX=max(MAX,f[i][k][1]*f[k+1][j][1]);
				MIN=min(MIN,f[i][k][1]*f[k+1][j][1]);
			}
		}
		f[i][j][0]=MAX;f[i][j][1]=MIN;
	}
	int ans=0,tot=0,out[55];
	for(int i=1;i<=N;i++){
		if(f[i][i+N-1][0]>ans){
			out[tot=1]=i;
			ans=f[i][i+N-1][0];
		}
		else if(f[i][i+N-1][0]==ans)
			out[++tot]=i;
	}
	printf("%d\n",ans);
	for(int i=1;i<=tot;i++)
		printf("%d ",out[i]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/WWWengine/article/details/82836208