zoukankan      html  css  js  c++  java
  • [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
    ",ans);
        for(int i=1;i<=n;i++)
    		if(f1[i][i+n-1]==ans)printf("%d ",i);
        return 0;
    }
    
    
  • 相关阅读:
    手机网络制式常识
    合并两个有序数组a和b到c
    N皇后问题
    数独求解
    ARM处理器模式
    ARM异常中断处理
    国风·召南·野有死麕
    八大排序算法
    1045 Favorite Color Stripe (最长不下降子序列 LIS 或最长公共子序列 LCS)
    1066 Root of AVL Tree (模拟AVL建树)
  • 原文地址:https://www.cnblogs.com/PPXppx/p/10925057.html
Copyright © 2011-2022 走看看