题面:
思路:
加强版的石子归并,现在朴素的区间dp无法解决问题了
首先我们破环成链,复制一条一样的链并粘贴到原来的链后面,变成一个2n长度的序列,在它上面dp,效率O(8n^3)
显然是过不了的,需要优化
注意:dp的转移如下:dp[i][j]=min(dp[i][k]+dp[k+1][j]+sum(i,j)),其中sum(i,j)表示i到j的价值和,满足区间单调性
因此dp[i][j]也满足区间单调性,可以用四边形不等式优化
我们令s[i][j]等于让dp[i][j]取最小值的那个K,根据优化,dp[i][j]的最优k值应该取在s[i][j-1]到s[i+1][j]中间
这样,效率变成了O(4n^2)的,能过了
Code:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #define inf 1e9 6 #define ll long long 7 using namespace std; 8 inline int read(){ 9 int re=0,flag=1;char ch=getchar(); 10 while(ch>‘9‘||ch<‘0‘){ 11 if(ch==‘-‘) flag=-1; 12 ch=getchar(); 13 } 14 while(ch>=‘0‘&&ch<=‘9‘) re=(re<<1)+(re<<3)+ch-‘0‘,ch=getchar(); 15 return re*flag; 16 } 17 int dp[2010][2010],s[2010][2010],pre[2010],n; 18 int main(){ 19 int i,j,k,l,tmp,ans=inf; 20 n=read(); 21 for(i=1;i<=n;i++) 22 dp[i][i]=read(),pre[i]=pre[i-1]+dp[i][i],s[i][i]=i; 23 memset(dp,0,sizeof(dp)); 24 for(l=2;l<=n;l++){ 25 for(i=1;i<=n-l+1;i++){ 26 j=i+l-1;dp[i][j]=inf; 27 for(k=s[i][j-1];k<=s[i+1][j];k++){ 28 tmp=dp[i][k]+dp[k+1][j]+pre[j]-pre[i-1]; 29 if(tmp<dp[i][j]){ 30 dp[i][j]=tmp;s[i][j]=k; 31 } 32 } 33 } 34 } 35 printf("%d",dp[1][n]); 36 }