• [NOI1995]石子合并 题解


    [NOI1995]石子合并 题解

    题面

    这是一道区间dp经典模板题

    思路

    - 容易想到设数组 (Fmax[i][j],Fmin[i][j]-->) 表示区间 (i)-(j) 的最大最小分数

    - 分析样例,考虑状态转移方程

        - Fmax[1][1]=a[1],Fmax[2][2]=a[2]
        - Fmax[1][2]=Fmax[1][1]+Fmax[2][2]+a[1-2]
          Fmax[2][3]=Fmax[2][2]+Fmax[3][3]+a[2-3]//必须在步骤3之前完成
        - Fmax[1][3]=Fmax[1][1]+Fmax[2][3]+a[1-3],Fmax[1][2]+Fmax[3][3]+a[1-3]
    

    - 由上推理可知需先枚举一个区间,再枚举起始点,最后枚举中间值

    - 状态转移方程由上可知为 (Fmax[i][j]=max(Fmax[i][k]+Fmax[k+1][j]+a[i-j],Fmax[i][j]))

    - 同理 (Fmin[i][j]=min(Fmin[i][k]+Fmin[k+1][j]+a[i-j],Fmin[i][j]))

    - (a[i-j]) 可用前缀和的形式表示为 (s[j]-s[i-1])

    - 由于是一个环,可以将其展开,用 (1 - (n+n)) 的形式

    Code 如下

    #include <iostream>
    #include <cstdlib>
    #include <cstdio>
    #include <cmath>
    #include <string>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int Max=2*101;
    int a[Max],s[Max];
    int Fmax[Max][Max];
    int Fmin[Max][Max];
    
    int main()
    {
    	memset(Fmax,0,sizeof(Fmax));
    	memset(Fmin,0,sizeof(Fmin));
    	int n;	scanf("%d",&n);
    	for(int i=1; i<=n; i++)	scanf("%d",a+i),s[i]=s[i-1]+a[i],a[i+n]=a[i];
    	for(int i=n+1; i<=n+n; i++)	s[i]=s[i-1]+a[i];
    	for(int q=1; q<n; q++)
    		for(int i=1,j=i+q; i<n+n&&j<n+n; i++,j=i+q)
    		{
    			Fmin[i][j]=0x7fffffff;
    			for(int k=i; k<j; k++)
    			{
    				Fmin[i][j]=min(Fmin[i][k]+Fmin[k+1][j]+s[j]-s[i-1],Fmin[i][j]),
    				Fmax[i][j]=max(Fmax[i][k]+Fmax[k+1][j]+s[j]-s[i-1],Fmax[i][j]);
    			}
    		}
    	int max1=0,min1=0x7fffffff;
    	for(int i=1; i<=n; i++)
    		max1=max(max1,Fmax[i][i+n-1]),
    		min1=min(min1,Fmin[i][i+n-1]);//展开每一个环的最大最小值
    	cout<<min1<<endl<<max1<<endl;
    	return 0;
    }
    
  • 相关阅读:
    v-bind v-on
    v-cloak v-text v- html
    centos 6.9安装 jdk
    容器数据卷创建
    MySQL 索引设计概要
    SQL EXPLAIN解析
    数据库范式(1NF/2NF/3NF)
    MySQL索引原理及慢查询优化
    InnoDB 的记录结构和页结构
    mysql explain type详解
  • 原文地址:https://www.cnblogs.com/vasairg/p/13280105.html
Copyright © 2020-2023  润新知