题意:
给定几堆石子,这几堆石子围成一个环,每次合并可以合并两堆相邻的石子,本次得分为这次合并的两堆石子数的和,多次合并后的得分加在一起。求最后合成一堆石子,最大得分和最小得分分别是多少?
这个题比较是比较经典的一个环处理的方法,就是把原来的数列再拷贝一份拼到数组后面,形成一个长度2n的序列。然后我们只需要考虑 合并[1,n],合并[2,n+1],合并[3,n+2],..........合并[n-1,2*n-1]的这些答案里面取一个最大和最小的即可,剩下的问题就是一个基础的石子合并的问题了。
关于合并石子,我用的记忆化,比较方便,循环推感觉不是很好考虑。(我是小菜)
注意如果l==r本次合并的代价是0,而不是a[l].
然后比较好考虑的一个性质是,合并一次[l,r]或者说本次合并[l,r]的花费等于sum_a[l][r]
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
int n;
int a[1007],sum[1007];
int dp[1007][1007],vis[1007][1007],ddp[1007][1007],vvis[1007][1007];
int dfs(int l,int r){
if(l==r){
return 0;
}
if(vis[l][r])return dp[l][r];
int ans=2147483647;
rep(i,l,r-1){
ans=min(ans,dfs(l,i)+dfs(i+1,r)+sum[r]-sum[l-1]);
}
vis[l][r]=1;
dp[l][r]=ans;
return ans;
}
int ddfs(int l,int r){
if(l==r){
return 0;
}
if(vvis[l][r])return ddp[l][r];
int ans=-1;
rep(i,l,r-1){
ans=max(ans,ddfs(l,i)+ddfs(i+1,r)+sum[r]-sum[l-1]);
}
vvis[l][r]=1;
ddp[l][r]=ans;
return ans;
}
int main(){
cin>>n;
rep(i,1,n){
cin>>a[i];
a[i+n]=a[i];
}
rep(i,1,2*n)sum[i]=sum[i-1]+a[i];
int ans=2147483647;
rep(i,1,n)ans=min(ans,dfs(i,i+n-1));
cout<<ans<<endl;
ans=-1;
rep(i,1,n)ans=max(ans,ddfs(i,i+n-1));
cout<<ans;
return 0;
}