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 }