[luogu P1880] [NOI1995]石子合并 {(环形)区间动态规划}

题目

https://www.luogu.org/problemnew/show/P1880


解题思路

对于环形的动态规划,我们用通用的方法是:将这一段重新复制一段放在原串后面。
动态规划方程很简单:

f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+sum[i][j]) f [ i ] [ j ] = m i n ( f [ i ] [ j ] , f [ i ] [ k ] + f [ k + 1 ] [ j ] + s u m [ i ] [ j ] )
f[i][j] f [ i ] [ j ] 表示合并从 i i j j minmax m i n 或 m a x 值, sum[i][j] s u m [ i ] [ j ] 可以用前缀和维护一下。


代码

#include
#include
#include
using namespace std;
const int mm=201;
int f[mm][mm],d[mm][mm],t[mm],s[mm],minn=1e9,maxx=-1e9,n,x;
int main()
{
    memset(f,127/3,sizeof(f));
    memset(d,-127/3,sizeof(d)); 
    scanf("%d",&n); 
    for (int i=1;i<=n;i++) scanf("%d",&t[i]); 
    for (int i=1;i<=(n<<1);i++){
     s[i]=s[i-1]+t[((i-1)%n)+1];
     f[i][i]=0; d[i][i]=0;  
    }
    n<<=1; 
    for (int i=n-1;i>=1;i--)
     for (int j=i+1;j<=n;j++)
      for (int k=i;k<=j-1;k++)
      {
         int y=s[j]-s[i-1]; 
         f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+y);
         d[i][j]=max(d[i][j],d[i][k]+d[k+1][j]+y); 
      }
    n>>=1; 
    for (int i=1;i<=n;i++)
     minn=min(minn,f[i][i+n-1]),maxx=max(maxx,d[i][i+n-1]); 
    printf("%d\n%d",minn,maxx);
}

你可能感兴趣的:(区间动态规划)