zoukankan      html  css  js  c++  java
  • P1880 [NOI1995]石子合并

    题目链接

    P1880 [NOI1995]石子合并

    思路

    区间dp啦啦啦啦

    首先就是要注意要把石子堆想成圈,不想估计也可以,不过我太菜了,咕咕咕

    用a数组是各堆的数量,max_dp数组是最大值,min_dp数组是最小值,容易得出枚举左右端点(l,r)和中间点(k)的方法,转移方程如下:

    [maxdp[i][j]=max(maxdp[i][j],maxdp[i][k]+maxdp[k+1][j]+a[j]-a[i-1]) ]

    [mindp[i][j]=min(mindp[i][j],mindp[i][k]+mindp[k+1][j]+a[j]-a[i-1]) ]

    因为如果打_会变成下标了,而且不知道为毛打不出来大括号,就这样看看吧

    代码(O(n^3))

    33ms / 1.39MB

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<map>
    #include<string>
    #include<cstring>
    using namespace std;
    inline int read() {
    	char c = getchar(); int x = 0, max_dp = 1;
    	while(c < '0' || c > '9') {if(c == '-') max_dp = -1; c = getchar();}
    	while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    	return x * max_dp;
    }
    int a[521],max_dp[521][521],min_dp[521][521];
    /*a数组是各堆的数量,max_dp数组是最大值,min_dp数组是最小值*/
    signed main() {
    	int n,maxn,minn;
    	scanf("%d",&n);
    	for(int i=1; i<=n; i++) {
    		scanf("%d",&a[i]);
    		a[n+i]=a[i];
    	}
    	for(int i=1; i<=2*n; i++)a[i]=a[i]+a[i-1]; //前缀和
    	for(int r=2; r<=n; r++) { //枚举起始点
    		for(int i=1; i<=2*n-r+1; i++) { //左端点
    			int j=i+r-1;//计算右端点 
    			max_dp[i][j]=max_dp[i+1][j]+a[j]-a[i-1];
    			min_dp[i][j]=min_dp[i+1][j]+a[j]-a[i-1];
    			for(int k=i; k<j; k++) {
    				max_dp[i][j]=max(max_dp[i][j],max_dp[i][k]+max_dp[k+1][j]+a[j]-a[i-1]);
    				min_dp[i][j]=min(min_dp[i][j],min_dp[i][k]+min_dp[k+1][j]+a[j]-a[i-1]);
    			}
    		}
    	}
    	maxn=max_dp[1][n],minn=min_dp[1][n];
    	for(int i=2; i<=n; i++) {
    		if(max_dp[i][i+n-1]>maxn)maxn=max_dp[i][i+n-1];
    		if(min_dp[i][i+n-1]<minn)minn=min_dp[i][i+n-1];
    	}
    	printf("%d
    %d",minn,maxn);
    	return 0;
    }
    

    高端做法

    四边形不等式优化(来自luogu题解第二篇),虽然我不会但是先写下来明天再搞

    代码:

    21ms / 9.18MB

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int a[2005],sum[2005];
    int fmi[2005][2005],fma[2005][2005],
        smi[2005][2005];
    
    int main(){
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            a[i+n]=a[i];
            sum[i]=sum[i-1]+a[i];
            smi[i][i]=i;
            }
        for(int i=1+n;i<=(n<<1);i++){
            sum[i]=sum[i-1]+a[i];
            smi[i][i]=i;
            }
        for(int i=(n<<1)-1;i;i--)
            for(int j=i+1;j<=(n<<1);j++){
                int jc=0,tmp=0x3f3f3f3f;
                fma[i][j]=max(fma[i][j-1],fma[i+1][j])+sum[j]-sum[i-1];
                /*注意这句,
                  求最大值不能用四边形不等式,
                  因为最大值不满足单调性,
                  但最大值有一个性质,
                  即总是在两个端点的最大者中取到。
                */
                for(int k=smi[i][j-1];k<=smi[i+1][j];k++){
                    int tt=fmi[i][k]+fmi[k+1][j]+(sum[j]-sum[i-1]);
                    if(tt<tmp){
                        tmp=tt;
                        jc=k;
                        }
                    }
                smi[i][j]=jc;
                fmi[i][j]=tmp;
                }
        int ama=0,ami=0x3f3f3f3f;
        for(int i=1;i<=n;i++){
            ama=max(ama,fma[i][i+n-1]);
            ami=min(ami,fmi[i][i+n-1]);
            }
        printf("%d
    %d",ami,ama);
    
        return 0;
        }
    
    $$Life quad is quad fantastic!$$
  • 相关阅读:
    使用密码记录工具keepass来保存密码
    ADO.NET Entity Framework CodeFirst 如何输出日志(EF 5.0)
    Mono 3.2 测试NPinyin 中文转换拼音代码
    Reactive Extensions(Rx) 学习
    Reactive Extensions介绍
    Mono 3.2 上跑NUnit测试
    RazorEngine 3.3 在Mono 3.2上正常运行
    标准数据源访问库
    .Net 跨平台可移植类库正在进行
    Windows安装和使用zookeeper
  • 原文地址:https://www.cnblogs.com/pyyyyyy/p/10908723.html
Copyright © 2011-2022 走看看