洛谷 P1880 [NOI1995]石子合并

洛谷 P1880 [NOI1995]石子合并

传送门:P1880 [NOI1995]石子合并

看了题目,我们显然的可以得知,这是一个dp,还是一个要用前缀和的dp。

还有,因为这是环形dp,我们要断环成链,将石子复制一份放在原数组的后面。

下面,蒟蒻代码:

#include<bits/stdc++.h>
using namespace std;
int i,j,k,m,n,s,ans,a[205],f1[205][205],f2[205][205],sum[205];//四个组分别为:石子、最小答案、最大答案、前缀和
int main()
{   scanf("%d",&n);
    for(i=1;i<=n;i++){
        scanf("%d",&a[i]);
        a[i+n]=a[i];//断环成链
    }
    for(i=1;i<=n*2;i++){
        for(j=1;j<=2*n;j++)
            f1[i][j]=2147483647;//预处理
        f1[i][i]=0,sum[i]=sum[i-1]+a[i];//预处理
    }
    for(s=1;s<n;s++)//枚举第一堆石子与第二堆石子的距离
        for(i=1;i<=2*n;i++){//第一堆石子
            int j=min(2*n,i+s);//第二堆石子
            for(k=i;k<j;k++)//开始找中间媒介
                f1[i][j]=min(f1[i][j],f1[i][k]+f1[k+1][j]+sum[j]-sum[i-1]),f2[i][j]=max(f2[i][j],f2[i][k]+f2[k+1][j]+sum[j]-sum[i-1]);//保存最大值,最小值
        }
    ans=2147483647;//开始枚举最小值
    for(i=1;i<=n;i++)
        ans=min(ans,f1[i][i+n-1]);
    printf("%d\n",ans);//输出
    ans=0;//开始枚举最大值
    for(i=1;i<=n;i++)
        ans=max(ans,f2[i][i+n-1]);
    printf("%d\n",ans);//输出
    return 0;
}

猜你喜欢

转载自blog.csdn.net/time_h/article/details/81569833