Luogu P4342 [IOI1998]Polygon

https://www.luogu.com.cn/problem/P4342

题面

每个顶点用整数标记,每个边用符号+(加)或符号*(乘积)标记。
每次可以删掉一条边,将两个点运算完和起来,问最大得分
\(n\leq 50\)

分析

显然区间DP,加法就是加法
由于数可能是负数,乘法需要将最小最大值乘起来
所以维护最小最大值即可

#include<bits/stdc++.h>
#define ll long long
const int INF=1e9;
using namespace std;

const int N=1005;
int n,a[N],f[N][N],g[N][N];
bool b[N];
char op[10];

int main() {
	scanf("%d",&n);
	for(int i=1;i<=n;i++) {
		scanf("%s%d",op,&a[i]);
		a[i+n]=a[i],b[i+n]=b[i]=(op[0]=='t')?0:1;
	}
	for(int i=1;i<=n+n;i++) {
		for(int j=1;j<=n+n;j++) f[i][j]=INF,g[i][j]=-INF;
	}
	for(int i=1;i<=n+n;i++) f[i][i]=g[i][i]=a[i];
	for(int l=2;l<=n;l++) {
		for(int i=1;i<=n+n-l+1;i++) {
			int j=i+l-1;
			for(int k=i+1;k<=j;k++) {
				if(b[k]==0) f[i][j]=min(f[i][k-1]+f[k][j],f[i][j]),g[i][j]=max(g[i][k-1]+g[k][j],g[i][j]);
					else {
						f[i][j]=min((ll)f[i][j],min((ll)f[i][k-1]*g[k][j],min((ll)g[i][k-1]*f[k][j],min((ll)f[i][k-1]*f[k][j],(ll)g[i][k-1]*g[k][j]))));
						g[i][j]=max((ll)g[i][j],max((ll)f[i][k-1]*g[k][j],max((ll)g[i][k-1]*f[k][j],max((ll)f[i][k-1]*f[k][j],(ll)g[i][k-1]*g[k][j]))));
					}
			}
		}
	}
	int Ans=0;
	for(int i=1;i<=n;i++) {
		Ans=max(Ans,g[i][i+n-1]);
	}
	printf("%d\n",Ans);
	for(int i=1;i<=n;i++) {
		if(g[i][i+n-1]==Ans) printf("%d ",i);
	}
	return 0;
}
posted @ 2020-11-30 19:07  wwwsfff  阅读(105)  评论(0)    收藏  举报