NOI1995 石子合并

25年前的人类智慧啊。

先考虑一个序列上的石子合并:

设f[i][j]是区间[i,j]合并得分的最大值

枚举要合并的区间长度len1~n,

枚举左端点i,j=i+len

枚举分割点k,

不难理解:f[i][j]=max(f1[i][j],f1[i][k]+f1[k+1][j]+d(i,j));

d(i,j)表示[i,j]的区间和,用前缀和计算即可

最小值同理。

对于环的处理:

拆开它?

数组展开到2n,然后进行dp,就能包含所有环形中可能出现的情况

最后枚举所有长度为n的区间取最值确定答案。

今天是2020-2-29,下次就该上带学了。

所以#define inf 20200229,

然后代码压到29行,纪念一下hhhhh

 1 #include<bits/stdc++.h>
 2 #define inf 20200229
 3 #define d(i,j) s[j]-s[i-1]
 4 using namespace std;
 5 int n,Min=inf,Max,f1[302][302],f2[302][302],a[302],s[302];
 6 int main(){
 7     cin>>n;
 8     for(int i=1;i<=n*2;i++){
 9         if(i<=n)
10       cin>>a[i];
11         a[i+n]=a[i];
12         s[i]=s[i-1]+a[i];
13     }
14     for(int len=1;len<n;len++){
15       for(int i=1,j=i+len;i<n*2&&j<n*2;i++,j=i+len){
16          f2[i][j]=inf;
17       for(int k=i;k<j;k++){
18           f1[i][j]=max(f1[i][j],f1[i][k]+f1[k+1][j]+d(i,j));
19           f2[i][j]=min(f2[i][j],f2[i][k]+f2[k+1][j]+d(i,j));
20       }
21     }
22   }
23     for(int i=1;i<=n;i++){
24       Max=max(Max,f1[i][i+n-1]);
25       Min=min(Min,f2[i][i+n-1]);
26   }    
27   cout<<Min<<endl<<Max;  
28   return 0;
29 }

 

posted @ 2020-02-29 22:43  _vv123  阅读(160)  评论(0编辑  收藏  举报