[IOI1998]Polygon

很早就看到这题了...但因为有个IOI标志,拖到现在才做

由于是以前在书上看到的,就没有想过其他算法,直接区间DP了...

方程式也挺好想的

跟我们平时做数学题求几个数乘积最大差不多

最大的*最大的

最小的*最小的(可能是负数)

这样两种情况

由于求最大中要用到最小值,我们在维护最大同时维护最小

最小的*最小的

最小的*最大的

也是两种情况

再考虑加法

最大:最大+最大

最小:最小+最小

各有一种情况

Tip 上面所述的类似于最大*最大都是左区间最大/小 和右区间最大/小

表达起来大概是这样的

	for(int len=2;len<=n;++len){
		for(int i=1;i+len-1<=2*n;++i){
			int j=i+len-1;
			for(int k=i;k<j;++k){
				if(opt[k+1]=='x')
					cmax(dpd[i][j],dpd[i][k]*dpd[k+1][j],dpx[i][k]*dpx[k+1][j]),
					cmin(dpx[i][j],dpd[i][k]*dpx[k+1][j],dpx[i][k]*dpd[k+1][j],dpx[i][k]*dpx[k+1][j]);
				else
					cmin(dpx[i][j],dpx[i][k]+dpx[k+1][j]),
					cmax(dpd[i][j],dpd[i][k]+dpd[k+1][j]);
			}
		}
	}

最后的代码

#include<cstdio>
#include<iostream>
#include<cstring>
#define inf (0x7fffffff)
#define writeln(x)  write(x),puts("")
#define writep(x)   write(x),putchar(' ')
using namespace std;
inline int read(){
	int ans=0,f=1;char chr=getchar();
	while(!isdigit(chr)){if(chr=='-') f=-1;chr=getchar();}
	while(isdigit(chr)){ans=(ans<<3)+(ans<<1)+chr-48;chr=getchar();}
	return ans*f;
}void write(int x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
}int n,a[155],dpx[155][155],dpd[155][155],ans=-inf;char opt[55];
inline void cmin(int &a,int b){if(b<a) a=b;}
inline void cmin(int &a,int b,int c){cmin(a,b),cmin(a,c);}
inline void cmin(int &a,int b,int c,int d){cmin(a,b,c),cmin(a,d);}
inline void cmax(int &a,int b){if(a<b)a=b;}
inline void cmax(int &a,int b,int c){cmax(a,b),cmax(a,c);}
 
int main(){
	n=read();
	for(register int i=1;i<=n;++i) cin>>opt[i]>>a[i];
	for(register int i=1;i<=n;++i) opt[i+n]=opt[i],a[i+n]=a[i];
	for(int i=1;i<=n*2;++i)
		for(int j=1;j<=n*2;++j)
			(i==j)?(dpx[i][i]=dpd[i][i]=a[i]):(dpd[i][j]=-inf,dpx[i][j]=inf);
	for(int len=2;len<=n;++len){
		for(int i=1;i+len-1<=2*n;++i){
			int j=i+len-1;
			for(int k=i;k<j;++k){
				if(opt[k+1]=='x')
					cmax(dpd[i][j],dpd[i][k]*dpd[k+1][j],dpx[i][k]*dpx[k+1][j]),
					cmin(dpx[i][j],dpd[i][k]*dpx[k+1][j],dpx[i][k]*dpd[k+1][j],dpx[i][k]*dpx[k+1][j]);
				else
					cmin(dpx[i][j],dpx[i][k]+dpx[k+1][j]),
					cmax(dpd[i][j],dpd[i][k]+dpd[k+1][j]);
			}
		}
	}
	for(int i=1;i<=n;++i) cmax(ans,dpd[i][i+n-1]);writeln(ans);
	for(int i=1;i<=n;i++) if(dpd[i][i+n-1]==ans) writep(i);
	return 0;
}

posted @ 2019-04-23 09:52  zheng_liwen  阅读(207)  评论(0编辑  收藏  举报
/*去广告*/