区间dp

Part1:总概

区间dp

顾名思义,就是解决一些区间内最优值的问题,通常的时间复杂度为 n 2 n^2 n2 或者 n 3 n^3 n3

大致思路:

  • 首先确定状态

  • 初始化长度为1(or 2,3…具体因题而异)的dp数组的值

  • 然后枚举区间长度,枚举区间的起始点,(有的题目还需要枚举断点) 由小区间转移到大区间。

  • 最后 d p [ 1 ] [ n ] dp[1][n] dp[1][n]往往就是答案。

Part2:例题精讲

NOI1995 石子合并

思路分析:

贪心~很明显是不行的

好的,那我们还是开始想dp吧。区间dp常用的一个状态就是dp[i][j]表示i~j这个区间的最优值是多少?

我们可以看出题目中这个合并过程,很像是区间dp的一种合并,也就是说 d p [ i ] [ j ] dp[i][j] dp[i][j]可以由 d p [ i ] [ k ] dp[i][k] dp[i][k] d p [ k + 1 ] [ j ] dp[k+1][j] dp[k+1][j]转移过
那么我们自然而然的想到要枚举上一次合并是在哪个位置,也就是断点k,然后进行转
不过,由于这个题目的特殊限制,我们需要记录g[i][j]表示i到j这个区间有多少石子,来进行辅助转移

f [ i ] [ j ] = m i n ( f [ i ] [ j ] , f [ i ] [ k ] + f [ k + 1 ] [ j ] + g [ i ] [ k ] + g [ k + 1 ] [ j ] ) ( i < = k < = j ) f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+g[i][k]+g[k+1][j]) ( i<=k<=j) f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+g[i][k]+g[k+1][j])(i<=k<=j)

对于环,我们只需要把整个数组复制一遍,然后在统计答案的时候,把1-n开头的长度为n的区间的答案求一个min 就可以啦

Code

#include
using namespace std;   
int n,minl,maxl,f1[300][300],f2[300][300],num[300];  
int s[300];  
int d(int i,int j)
{
    return s[j]-s[i-1];
}  
int main()
{
    cin>>n;
    for(int i=1;i<=n+n;i++)  
    {  
        cin>>num[i]; 
        num[i+n]=num[i];  
        s[i]=s[i-1]+num[i];  
    }  
    for(int p=1;p<n;p++)  
    {  
        for(int i=1,j=i+p;(j<n+n)&&(i<n+n);i++,j=i+p)  
        {  
            f2[i][j]=999999999;  
            for(int k=i;k<j;k++)  
            {  
                f1[i][j]=max(f1[i][j],f1[i][k]+f1[k+1][j]+d(i,j));   
                f2[i][j]=min(f2[i][j],f2[i][k]+f2[k+1][j]+d(i,j));  
            }  
        }  
    }  
    minl=999999999;  
    for(int i=1;i<=n;i++)  
    {  
        maxl=max(maxl,f1[i][i+n-1]);
        minl=min(minl,f2[i][i+n-1]);  
    }
    cout<<minl<<endl<<maxl;
    return 0;  
}

不过,这道题在hdu上(hdu3506)n^3的时间复杂度过不了

那么我们就需要考虑,四边形不等式优化!!

如果有 f [ a ] [ c ] + f [ b ] [ d ] < = f [ b ] [ c ] + f [ a ] [ d ] f[a][c]+f[b][d]<=f[b][c]+f[a][d] f[a][c]+f[b][d]<=f[b][c]+f[a][d]
可以理解为一句话,交叉小于包含,即交叉的两个区间,a到c和b到d的值满足小于等于包含的两个区间[bc包含于ad])

则说这个东西满足四边形不等式,当然这个东西可能是dp数组,也可以是其他数组

这里有两个定理

1、如果上述的w函数同时满足区间包含单调性和四边形不等式性质,那么函数dp也满足四边形不等式性质

我们再定义 s ( i , j ) s(i,j) s(i,j)表示 d p ( i , j ) dp(i,j) dp(i,j) 取得最优值时对应的下标(即 i ≤ k ≤ j i≤k≤j ikj 时,k 处的 dp 值最大,则 s ( i , j ) = k s(i,j)=k s(i,j)=k此时有如下定理

2、假如 d p ( i , j ) dp(i,j) dp(i,j)满足四边形不等式,那么 s ( i , j ) s(i,j) s(i,j)单调,即 s ( i , j ) ≤ s ( i , j + 1 ) ≤ s ( i + 1 , j + 1 ) s(i,j)≤s(i,j+1)≤s(i+1,j+1) s(i,j)s(i,j+1)s(i+1,j+1)

那么我们就可以开一个s数组 , s [ i ] [ j ] s[i][j] s[i][j]这个数组记录 i   j i~j i j这个区间的转移的最优点是哪个点

那么枚举断点是时候 直接可以从 s [ i ] [ j − 1 ]   s [ i + 1 [ j ] s[i][j-1] ~ s[i+1[j] s[i][j1] s[i+1[j]枚举转移

(1)当函数w[i,j]满足 w [ i , j ] + w [ i ′ , j ′ ] < = w [ i ′ , j ] + w [ i , j ′ ] , i < = i ′ < = j < = j ′ w[i,j]+w[i',j']<=w[i',j]+w[i,j'],i<=i'<=j<=j' w[i,j]+w[i,j]<=w[i,j]+w[i,j],i<=i<=j<=j时,称w满足四边形不等式。

(2)当函数w[i,j]满足 w [ i ’ , j ] ≤ w [ i , j ’ ] , i < = i ′ < = j < = j ′ w[i’,j]≤w[i,j’],i<=i'<=j<=j' w[i,j]w[i,j],i<=i<=j<=j时称w关于区间包含关系单调。

很明显的,一开始定义的w[I,j]满足区间包含关系和四边形不等式。

现在我们要证明 f [ I , j ] = m i n f [ I , k ] + f [ k + 1 , j ] + w [ I , j ] i < = k < j f[I,j]=min{f[I,k]+f[k+1,j]+w[I,j]}{i<=kf[I,j]=minf[I,k]+f[k+1,j]+w[I,j]i<=k<j也满足四边形不等式

我们利用数学归纳法对四边形不等式中的区间长度进行归纳。

证明如下

当i=i’或j=j’时,不等式显然成立。由此可知,当l≤1时,函数f满足四边形不等式。

下面分两种情形进行归纳证明:

  • 情形1: i < i ’ = j < j ’ ii<i=j<j
    在这种情形下,四边形不等式简化为如下的不等式: f [ i , j ] + f [ j , j ’ ] ≤ f [ i , j ’ ] + 0 f[i,j]+f[j,j’] ≤f[i,j’]+0 f[i,j]+f[j,j]f[i,j]+0,设 k = m a x p ∣ f [ i , j ’ ] = f [ i , p − 1 ] + f [ p , j ’ ] + w [ i , j ’ ] k=max{p| f[i,j’]=f[i,p-1]+f[p,j’]+w[i,j’] } k=maxpf[i,j]=f[i,p1]+f[p,j]+w[i,j],再分两种情形 k ≤ j k≤j kj k > j k>j k>j。下面只讨论 k ≤ j k≤j kj k > j k>j k>j 的情况是类似的。

  • 情形1.1: k ≤ j k≤j kj,此时:

  • 情形1.2: k > j k>j k>j,略去

  • 情形2: i < i ’ < j < j ’ ii<i<j<j
    y = m a x p ∣ f [ i ’ , j ] = f [ i ’ , p − 1 ] + f [ p , j ] + w [ i ’ , j ] y=max{p | f[i’,j]=f[i’,p-1]+f[p,j]+w[i’,j] } y=maxpf[i,j]=f[i,p1]+f[p,j]+w[i,j] f [ p , j ’ ] + w [ i , j ’ ] {f[p,j’]+w[i,j’] } f[p,j]+w[i,j]
    仍需再分两种情形讨论,即 z ≤ y z≤y zy z > y z>y z>y。下面只讨论 z ≤ y z≤y zy z > y z>y z>y的情况是类似的。
    情形2.1, i < z ≤ y ≤ j ii<zyj
    显然的,我们有:
    f [ i , j ] + f [ i ′ , j ′ ] < = w [ i , j ] + f [ i , z − 1 ] + f [ z , j ] + w [ i ′ , j ′ ] + f [ i ′ , y − 1 ] + f [ y , j ′ ] f[i,j]+f[i',j']<=w[i,j]+f[i,z-1]+f[z,j]+w[i',j']+f[i',y-1]+f[y,j'] f[i,j]+f[i,j]<=w[i,j]+f[i,z1]+f[z,j]+w[i,j]+f[i,y1]+f[y,j]
    因为w满足四边形不等式,所以:
    f [ i , j ] + f [ i ′ , j ′ ] < = w [ i , j ′ ] + w [ i ′ , j ] + f [ i ′ , y − 1 ] + f [ i , z − 1 ] + f [ z , j ] + f [ y , j ′ ] f[i,j]+f[i',j']<=w[i,j']+w[i',j]+f[i',y-1]+f[i,z-1]+f[z,j]+f[y,j'] f[i,j]+f[i,j]<=w[i,j]+w[i,j]+f[i,y1]+f[i,z1]+f[z,j]+f[y,j]
    因为 f [ i , j ′ ] + f [ i ′ , j ] = w [ i , j ′ ] + w [ i ′ , j ] + f [ i ′ , y − 1 ] + f [ i , z − 1 ] + f [ y , j ] + f [ z , j ′ ] f[i,j']+f[i',j]=w[i,j']+w[i',j]+f[i',y-1]+f[i,z-1]+f[y,j]+f[z,j'] f[i,j]+f[i,j]=w[i,j]+w[i,j]+f[i,y1]+f[i,z1]+f[y,j]+f[z,j]
    所以,要证 f [ i , j ′ ] + f [ i ′ j ] > = f [ i , j ] + f [ i ′ , j ′ ] f[i,j']+f[i'j]>=f[i,j]+f[i',j'] f[i,j]+f[ij]>=f[i,j]+f[i,j],就要证 f [ z , j ] + f [ y , j ′ ] < = f [ y , j ] + f [ z , j ′ ] f[z,j]+f[y,j']<=f[y,j]+f[z,j'] f[z,j]+f[y,j]<=f[y,j]+f[z,j]
    因为 i < z ≤ y ≤ j ii<zyj,所以区间的长度会在不断地迭代中越变越小,最后归于前面的几种情况。

  • 情形2.1, i < y ≤ z ≤ j ii<yzj。证明过程略。
    综上所述, f [ i , j ] f[i,j] f[i,j]满足四边形不等式。
    事实上,对于任意 f [ I , j ] = m a x f [ I , k ] + f [ k + 1 , j ] + w [ I , j ] i < = k < j f[I,j]=max{f[I,k]+f[k+1,j]+w[I,j]}{i<=kf[I,j]=maxf[I,k]+f[k+1,j]+w[I,j]i<=k<j,如果w满足四边形不等式,那么f也满足四边形不等式。
    前面千辛万苦证明了f满足四边形不等式,那么它有什么用呢?
    之所以要证明四边形不等式,就是为了证明f满足决策单调性,即:
    s [ i , j − 1 ] ≤ s [ i , j ] ≤ s [ i + 1 , j ] , i ≤ j s[i,j-1]≤s[i,j]≤s[i+1,j], i≤j s[i,j1]s[i,j]s[i+1,j],ij
    其中, s [ I , j ] s[I,j] s[I,j]为区间 [ I , j ] [I,j] [I,j]上的最优决策。
    i = j i=j i=j时,单调性显然成立。因此下面只讨论 i < j ii<j的情形。由于对称性,只要证明 s [ i , j ] ≤ s [ i , j + 1 ] s[i,j]≤s[i,j+1] s[i,j]s[i,j+1]
    f k [ i , j ] = f [ i , k − 1 ] + f [ k , j ] + w [ i , j ] fk[i,j]=f[i,k-1]+f[k,j]+w[i,j] fk[i,j]=f[i,k1]+f[k,j]+w[i,j]。要证明 s [ i , j ] ≤ s [ i , j + 1 ] s[i,j]≤s[i,j+1] s[i,j]s[i,j+1],只要证明对于所有 i < k ≤ k ’ ≤ j ii<kkj f k ’ [ i , j ] ≤ f k [ i , j ] fk’[i,j]≤fk[i,j] fk[i,j]fk[i,j],有: f k ’ [ i , j + 1 ] ≤ f k [ i , j + 1 ] fk’[i,j+1]≤fk[i,j+1] fk[i,j+1]fk[i,j+1]
    事实上,我们可以证明一个更强的不等式

f k [ i , j ] − f k ’ [ i , j ] ≤ f k [ i , j + 1 ] − f k ’ [ i , j + 1 ] fk[i,j]-fk’[i,j]≤fk[i,j+1]-fk’[i,j+1] fk[i,j]fk[i,j]fk[i,j+1]fk[i,j+1]

也就是: f k [ i , j ] + f k ’ [ i , j + 1 ] ≤ f k [ i , j + 1 ] + f k ’ [ i , j ] fk[i,j]+fk’[i,j+1]≤fk[i,j+1]+fk’[i,j] fk[i,j]+fk[i,j+1]fk[i,j+1]+fk[i,j]

利用递推定义式将其展开整理可得: f [ k , j ] + f [ k ’ , j + 1 ] ≤ f [ k ’ , j ] + f [ k , j + 1 ] f[k,j]+f[k’,j+1]≤f[k’,j]+f[k,j+1] f[k,j]+f[k,j+1]f[k,j]+f[k,j+1],这正是 k ≤ k ’ ≤ j < j + 1 k≤k’≤jkkj<j+1时的四边形不等式

综上所述,当 w w w满足四边形不等式时,函数 s [ i , j ] s[i,j] s[i,j]具有单调性。

因此,我们可以得到一个更优化的转移方程

上述方法利用四边形不等式推出最优决策的单调性,从而减少每个状态转移的状态数,降低算法的时间复杂度。

这样这道题就解决了。

一般的,对于状态转移方程形如: f [ i , j ] = o p t f [ i , k ] + f [ k + 1 , j ] + w [ i , j ] , i < j f[i , j] = opt{f[i , k] + f[k+1 , j]} + w[i , j], i < j f[i,j]=optf[i,k]+f[k+1,j]+w[i,j],i<j的动规,若w满足四边形不等式,则f满足四边形不等式,则f有决策单调性。

Code

#include 
#include 
#include 
#include 
 
using std::max;
using std::min;
 
const int maxn=300;
 
int base[maxn];
int dp[maxn][maxn],s[maxn][maxn];
int MAX[maxn][maxn];
 
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&base[i]);
        base[i+n]=base[i];
    }
    for(int i=1;i<=n*2;i++)
        base[i]+=base[i-1];
    for(int i=1;i<=n*2;i++)
        s[i][i]=i;
    for(int l=2;l<=n;l++)
        for(int i=1;i<=(n*2)-l+1;i++)
        {
            int j=i+l-1;
            int x=s[i][j-1],y=s[i+1][j];
            dp[i][j]=0x7fffffff;
            MAX[i][j]=max(MAX[i][j-1],MAX[i+1][j])+base[j]-base[i-1];//最大值不满足四边形不等式,但最有决策一定出现在端点处
            for(int k=x;k<=y;k++)
                if(dp[i][k]+dp[k+1][j]+base[j]-base[i-1]<dp[i][j])
                {
                    dp[i][j]=dp[i][k]+dp[k+1][j]+base[j]-base[i-1];
                    s[i][j]=k;
                }
        }
    int ansMin=0x7fffffff,ansMax=0;
    for(int i=1;i<n;i++)
        ansMin=min(ansMin,dp[i][i+n-1]),
        ansMax=max(ansMax,MAX[i][i+n-1]);
    printf("%d\n%d",ansMin,ansMax);
    return 0;
}

hdu4632 **

思路:

大致题意是给定一个字符串,求回文子序列个数,最后的答案要%10007,要求一个n^2的做法

首先定义f数组 f [ l ] [ r ] f[l][r] f[l][r]表示 l   r l~r l r区间的回文子序列个数, f [ i ] [ i ] = 1 f[i][i]=1 f[i][i]=1;

显然 根据容斥原理 : f [ l ] [ r ] = f [ l ] [ r − 1 ] + f [ l + 1 ] [ r ] − f [ l + 1 ] [ r − 1 ] f[l][r]=f[l][r-1]+f[l+1][r]-f[l+1][r-1] f[l][r]=f[l][r1]+f[l+1][r]f[l+1][r1] (因为中间的个数会算两遍);

然后,我们考虑 s [ l ] = = s [ r ] s[l]==s[r] s[l]==s[r]的情况,如果这两个位置相等,那么 l + 1   r − 1 l+1 ~ r-1 l+1 r1这个区间的所有子序列,都可以加入l和r这两个元素,构成一个新的回文子序列,除此之外 l和r这两个元素也可以构成一个回文子序列

那么 i f ( s [ l ] = = s [ r ] ) f [ l ] [ r ] + = f [ l + 1 ] [ r − 1 ] + 1 if (s[l]==s[r]) f[l][r]+=f[l+1][r-1]+1 if(s[l]==s[r])f[l][r]+=f[l+1][r1]+1;
Attention
做减法的时候,可能会有负数,为了使%不出现问题,我们需要先加mod再%mo

Code:

#inclue
using namespace std;
#define inf 0x3f3f3f3f
#define mod 10007
int dp[1005][1005];
char s[1005]
int main()
{
	int t,cas=1;
    cin>>t;
    while(t--)
    {
        cin>>s;
        int len=strlen(s);
        memset(dp,0,sizeof dp);
        for(int i=0;i<len;i++)
            dp[i][i]=1;
        for(int j=0;j<len;j++)
        {
            for(int i=j-1;i>=0;i--)
            {
                dp[i][j]=(dp[i][j-1]+dp[i+1][j]-dp[i+1][j-1]+mod)%mod;
                if(s[i]==s[j])
                    dp[i][j]=(dp[i][j]+dp[i+1][j-1]+1)%mod;
            }
        }
        printf("Case %d: %d\n",cas++,dp[0][len-1]);
    }
    return 0;
}

hdu4745*********

题目大意:

给定一个数列,求一个最长的回文子序列

思路:

我们定义 f [ l ] [ r ] f[l][r] f[l][r]表示l到r区间的最长的回文子序列长度

如果 s [ l ] = = s [ r ] s[l]==s[r] s[l]==s[r] f [ l ] [ r ] = f [ l + 1 ] [ r − 1 ] + 2 f[l][r]=f[l+1][r-1]+2 f[l][r]=f[l+1][r1]+2;

不然 f [ l ] [ r ] = m a x ( f [ l + 1 ] [ r ] , f [ l ] [ r − 1 ] ) f[l][r]=max(f[l+1][r],f[l][r-1]) f[l][r]=max(f[l+1][r],f[l][r1]);

然后统计答案的时候

因为是环

由于考虑到可以从

同一个点出发,长度为n-1,+1

或者从不同的点出发,长度为n

Code:

#include 
#include 
#include 
#include 
#include 
using namespace std;
int s[1005],dp[2005][2005];
int main(){                                     //一个顺时针一个逆时针,并且元素
    int n,i,j,l,ans;                            //相同,因此相当于在环上求最长回
    while(scanf("%d",&n)!=EOF&&n){              //文子序列
        memset(dp,0,sizeof(dp));
        for(i=1;i<=n;i++){
            scanf("%d",&s[i]);
            s[i+n]=s[i];
            dp[i][i]=dp[i+n][i+n]=1;
        }
        for(l=2;l<=2*n;l++){
            for(i=1;i<=2*n-l+1;i++){
                j=i+l-1;
                dp[i][j]=max(dp[i+1][j],dp[i][j-1]);
                if(s[i]==s[j])
                dp[i][j]=max(dp[i][j],dp[i+1][j-1]+2);
            }
        }                                       //当s[i]==s[j]时长度加2
        ans=0;
        for(i=1;i<=n;i++){                      //因为是环,所以起点可能在一个点,
            ans=max(ans,dp[i][i+n-1]);          //这样只需求长度是n-1的再加1即可
            ans=max(ans,dp[i][i+n-2]+1);
        }
        printf("%d\n",ans);
    }
    return 0;
}

hdu2476******

题目大意:

给定一个A串,一个B串,每次修改只能将一段连续区间内的字母,改成同一个字母,询问将A变成B 的最少操作次数

思路:

因为考虑到有相等的和不相等的部分,所以不能直接做

先假设A和B所有的对应位置都不相等,然后令 f [ l ] [ r ] f[l][r] f[l][r]表示l~r这个区间最小操作的次数

然后对一个区间l r 我们可以考虑,首先将 f [ l ] [ r ] = f [ l + 1 ] [ r ] + 1 f[l][r]=f[l+1][r]+1 f[l][r]=f[l+1][r]+1;表示需要在上一个区间的基础上,额外操作一次。然后枚举一个 k k k

l + 1 l+1 l+1 r r r,如果 b [ k ] = = b [ l ] b[k]==b[l] b[k]==b[l] 那么 l这个位置 就可以在刷k的时候 刷上,而且不影响之前的区间。

f [ l ] [ r ] = m i n ( f [ l ] [ r ] , f [ l ] [ k ] + f [ k + 1 ] [ r ] ) f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]) f[l][r]=min(f[l][r],f[l][k]+f[k+1][r])

然后 我们令 a n s [ i ] ans[i] ans[i]表示A的第1到第 i i i 刷成和 B B B相同的 需要的 最小的操作次数

a [ i ] = = b [ i ] a[i]==b[i] a[i]==b[i] a n s [ i ] = a n s [ i − 1 ] ans[i]=ans[i-1] ans[i]=ans[i1] (因为不需要刷)

else 枚举一个j 表示这个 a n s [ i ] ans[i] ans[i]从哪个答案转移过来

a n s [ i ] = m i n ( a n s [ i ] , a n s [ j ] + f [ j + 1 ] [ i ] ) ans[i]=min(ans[i],ans[j]+f[j+1][i]) ans[i]=min(ans[i],ans[j]+f[j+1][i]);

hdu4283 ********

题目大意:

现在给定一个序列,表示每个人的不开心值D,假如他是第x个上场,那他就有(x-1)*D的不开心值,因为他等了k-1个人,你有一个类似于栈的东西,可以使用它来改变整个序列的顺序,求最少的 不开心值的和

思路:

由于修改顺序的时候,是要用类似栈的方式QWQ所以没法贪心…

这个题有一个性质,若第i个人是通过栈调整之后,第k个表演的 那么他能造成的影响 是可以比较容易计算的。

我们令 f [ l ] [ r ] f[l][r] f[l][r]表示 l   r l~r l r这些人的最小等待时间

首先预处理一下所有人的等待时间的前缀和 s u m [ i ] sum[i] sum[i],便于计算

对于一个区间 [ l , r ] [l,r] [l,r] 我们枚举第l个人是第几个出去的

k k k l   r l~r l r

假设他是第k个出去的

f [ l ] [ r ] = m i n ( f [ l ] [ r ] , f [ l + 1 ] [ k ] + f [ k + 1 ] [ r ] + ( k − l ) ∗ a [ i ] + ( k − l + 1 ) ∗ ( s u m [ r ] − s u m [ k ] ) ) f[l][r]=min(f[l][r],f[l+1][k]+f[k+1][r]+(k-l)*a[i]+(k-l+1)*(sum[r]-sum[k])) f[l][r]=min(f[l][r],f[l+1][k]+f[k+1][r]+(kl)a[i]+(kl+1)(sum[r]sum[k]))

这里有几个要注意的地方:

  • f [ l + 1 ] [ k ] f[l+1][k] f[l+1][k] 而不是 f [ l ] [ k ] f[l][k] f[l][k] 因为这里枚举的就是第 l l l个人的出栈顺序

  • 2 > ( k − l ) 2>(k-l) 2>(kl)表示在这个人之前有几个人出去 ( k − 1 + 1 ) (k-1+1) k1+1表示算上这个人 出去了几个人

poj2955

题目大意

给定一个只含小括号和中括号的序列,求一个最长的合法序列。

其中() [] ()[] (()) 等 是合法的

)( (] 等 是不合法的

思路

由于两个本身合法的序列拼在一起也是合法的序列,所以我们自然而然的就想到

f [ l ] [ r ] f[l][r] f[l][r]表示 l   r l~r l r这个区间的最长合法序列的程度

根据 a [ l ] a [ r ] f [ l + 1 ] [ r − 1 ] a[l] a[r] f[l+1][r-1] a[l]a[r]f[l+1][r1]进行初始化

然后枚举断点,进行转移

这里有一个小tip就是

可以把左右括号分别变成正负的数字,便于判断

poj1651

题目大意

给定你一个序列

其中取走一个数的代价是它乘上它相邻的两个数

两头的数不可以取~

求最小代价

思路

f [ l ] [ r ] f[l][r] f[l][r]表示把 l + 1   r − 1 l+1 ~ r-1 l+1 r1的数都取走的最小代价

首先初始化 f [ i ] [ i + 2 ] f[i][i+2] f[i][i+2]这个区间

然后之后枚举长度,起始点,断点,进行转移即可

f [ l ] [ r ] = m i n ( f [ l ] [ r ] , f [ l ] [ k ] + f [ k ] [ r ] + a [ l ] ∗ a [ k ] ∗ a [ r ] f[l][r]=min(f[l][r],f[l][k]+f[k][r]+a[l]*a[k]*a[r] f[l][r]=min(f[l][r],f[l][k]+f[k][r]+a[l]a[k]a[r];

你可能感兴趣的:(区间dp)