zoukankan      html  css  js  c++  java
  • [Solution] [IOI1998]Polygon

    区间DP

    Link

    • 和石子合并类似。新增了乘法运算符。

    • 思路:

      • 拆环为链

        • t -7 t 4 x 2 x 5  --->   t -7 t 4 x 2 x 5 t -7 t 4 x 2 x 5
          
        • 这么干的好处是,不用考虑圆环的首尾相接处的特殊处理。

      • 状态设计

        • (F[L][L+N])就是拆除了边(L)后的最佳结果。
        • 对于乘法来说,有的规则似乎不适用。例如 负负得正。但是,经过一些简单的数学推导可以得出,最大值可能来自于两个小负数相乘,或者两个大证书相乘。
        • 进一步归纳,就是 同号两数相乘,且两数绝对值较大
        • (FMax]][])(FMin[][])分别维护绝对值最大的正数和负数。
      • 状态转移

        • 对于加法,按照普遍的经验即可。
        • 重点是乘法,牢记同号得正,异号得负
    • 参考代码及注释

      #include <stdio.h>
      #include <string.h>
      #define Clean(X,K) memset(X,K,sizeof(X))
      #define GC getchar()
      #define Min(X,Y) (X<Y?X:Y)
      #define Max(X,Y) (X>Y?X:Y)
      
      int Qread () {
      	int X = 0 , F = 1;
      	char C = GC ;
      	while (C > '9' || C < '0') {
      		if (C == '-') F = -1 ;
      		C = GC ;
      	}
      	while (C >='0' && C <='9') {
      		X = X * 10 + C - '0' ;
      		C = GC ;
      	}
      	return X *F ;
      }
      
      const int Maxn = 52 , INF = 20021020;
      int N , A[Maxn << 1] , F_Max[Maxn << 1][Maxn << 1] , F_Min[Maxn << 1][Maxn << 1];
      char O[Maxn << 1];
      /*
      变量名解释
      A[]:原始数据
      O[]:原始运算符 
      F_Max[Maxn << 1][Maxn << 1] , F_Min[Maxn << 1][Maxn << 1]:分别维护绝对值最大的正数和负数 
      */
      int main () {
      	Clean (F_Max , ~0x3f) , Clean (F_Min , 0x3f) ;
      
      //	freopen ("Polygon.txt" , "r" , stdin) ;
      	N = Qread () ;
      	for (int i = 1 ; i <= N; ++ i) {
      		do {
      			O[i] = O[i + N] = GC ;
      		} while (O[i] != 't' && O[i] != 'x');
      		A[i] = A[i + N] = F_Max[i][i] = F_Min[i][i] = F_Max[i + N][i + N] = F_Min[i + N][i + N] = Qread () ;
      	}
      	
      	for (int Len = 2 ; Len <= N ; ++ Len) {
      		for (int St = 1 ; St <= (N << 1) - Len; ++ St) {
      			for (int K = St ; K < St + Len - 1 ; ++ K) {
      				/*
      				Len : 枚举区间的长度
      				St :区间的左端点
      				K :把区间分成 [St,K]和[K + 1,St + Len - 1]两部分 
      				*/
      				if (O[K + 1] == 't') {
      					F_Max[St][St + Len - 1] = Max (F_Max[St][St + Len - 1] , F_Max[St][K] + F_Max[K + 1][St + Len - 1]) ;
      					F_Min[St][St + Len - 1] = Min (F_Min[St][St + Len - 1] , F_Min[St][K] + F_Min[K + 1][St + Len - 1]) ;
      				} else {
      					F_Max[St][St + Len - 1] = Max (F_Max[St][St + Len - 1] , F_Min[St][K] * F_Min[K + 1][St + Len - 1]) ;
      					F_Max[St][St + Len - 1] = Max (F_Max[St][St + Len - 1] , F_Max[St][K] * F_Max[K + 1][St + Len - 1]) ;
      					//负负得正,取得较大值 
      					F_Min[St][St + Len - 1] = Min (F_Min[St][St + Len - 1] , F_Max[St][K] * F_Min[K + 1][St + Len - 1]) ;
      					F_Min[St][St + Len - 1] = Min (F_Min[St][St + Len - 1] , F_Min[St][K] * F_Max[K + 1][St + Len - 1]) ;
      					//正负得负,取得较小值 
      				}
      			}
      		}
      	}
      	
      	int Ans = -INF ;
      	for (int i = 1 ; i <= N; ++ i) Ans = Max (Ans , F_Max[i][i + N - 1]) ;
      	printf ("%d
      " , Ans) ;
      	for (int i = 1 ; i <= N; ++ i) if (Ans == F_Max[i][i + N - 1]) printf ("%d " , i) ;
      	fclose (stdin) , fclose (stdout) ;
      	return 0 ;
      }
      

    Thanks!

  • 相关阅读:
    Centos安装mysql
    @autowired注解报错原因及解决办法
    注解@Resource与@Autowired的区别
    SpringBoot三种获取Request和Response的方法
    oss 上传图片、下载 中文名称
    git tags 和 Branches的区别是什么呀,什么时候应该创建一个Tag?
    git使用命令,git checkout -b a 与 git branch a区别
    PostgreSQL-With子句实现递归
    redisson锁 tryLock的使用及正确用法
    mysql any 和in 函数的使用
  • 原文地址:https://www.cnblogs.com/bj2002/p/11288853.html
Copyright © 2011-2022 走看看