[IOI1998]Polygon

POJ

洛咕

题意:给定一个n个顶点n条边的多边形,每个顶点上有一个整数,每条边上有一个乘号或加号,第一次任意删去一条边,之后每次合并两个顶点为一个顶点,求只剩最后一个顶点是的最大值及有多少种方法得到这个最大值.

分析:有一个环,先删去一条边后变成一条链,每次合并两个顶点,要获得最大值,那就用区间DP好了.对于第一个操作"任意删去一条边"很好处理,直接断环为链,然后把链倍长.

然后就是区间DP的模板了,先枚举区间长度len,然后枚举左端点i,再用len和i表示出右端点j,最后枚举区间断点k.

至于状态转移,我们一个一个来分析.首先肯定要分乘号和加号两种情况讨论,然后再想想对于一次乘法运算要得到最大值,有两种情况,一是两个很大的正数相乘,而是两个很小的负数相乘,所以我们需要开两个数组,\(f1[i][j]\)表示合并区间\([i,j]\)得到的最大值,\(f2[i][j]\)表示合并区间\([i,j]\)得到的最小值.两个数组都要维护.

对于乘法运算,要得到最大值正如上段所述,

\(f1[i][j]=max(f1[i][j],max(f1[i][k]*f1[k+1][j],f2[i][k]*f2[k+1][j]))\)

要得到最小值,干脆把所有情况取min好了,

\(f2[i][j]=min(f2[i][j],min(f2[i][k]*f2[k+1][j],min(f1[i][k]*f1[k+1][j],min(f1[i][k]*f2[k+1][j],f2[i][k]*f1[k+1][j]))))\)

对于加法运算,就很容易了,

\(f1[i][j]=max(f1[i][j],f1[i][k]+f1[k+1][j])\)

\(f2[i][j]=min(f2[i][j],f2[i][k]+f2[k+1][j])\)

//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
inline int read(){
   int s=0,w=1;char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
   return s*w;
}
int a[105],f1[150][150],f2[150][150];
char ch[105];
int main(){
    int n;cin>>n;
    for(int i=1;i<=n;i++){
        cin>>ch[i]>>a[i];
        a[n+i]=a[i];ch[n+i]=ch[i];
    }
    for(int i=1;i<=n*2;i++)
	f1[i][i]=f2[i][i]=a[i];
    for(int len=2;len<=n;len++){
        for(int i=1;i<=2*n-len+1;i++){
	    	int j=i+len-1;f1[i][j]=-1e9,f2[i][j]=1e9;
            for(int k=i;k<j;k++){
                if(ch[k+1]=='x'){
		    		f1[i][j]=max(f1[i][j],max(f1[i][k]*f1[k+1][j],f2[i][k]*f2[k+1][j]));
		    		f2[i][j]=min(f2[i][j],min(f2[i][k]*f2[k+1][j],min(f1[i][k]*f1[k+1][j],min(f1[i][k]*f2[k+1][j],f2[i][k]*f1[k+1][j]))));
                }
                else if(ch[k+1]=='t'){
                    f1[i][j]=max(f1[i][j],f1[i][k]+f1[k+1][j]);
                    f2[i][j]=min(f2[i][j],f2[i][k]+f2[k+1][j]);
                }
            }
        }
    }
    int ans=-1e9;
    for(int i=1;i<=n;i++)
		ans=max(ans,f1[i][i+n-1]);
    printf("%d\n",ans);
    for(int i=1;i<=n;i++)
		if(f1[i][i+n-1]==ans)printf("%d ",i);
    return 0;
}

posted on 2019-05-26 09:08  PPXppx  阅读(122)  评论(0编辑  收藏  举报