很显然可以把这个过程反过来计算贡献。
所以这就是道石子合并。
顺便打一下四边形不等式。
四边形不等式
对于方程形式如下的一类
2
D
/
1
D
2D/1D
2D/1D动态规划问题(多是区间DP)
f
(
i
,
j
)
=
m
i
n
{
f
(
i
,
k
)
+
f
(
k
+
1
,
j
)
+
w
(
i
,
j
)
}
f(i,j)=min\{f(i,k)+f(k+1,j)+w(i,j)\}
f(i,j)=min{f(i,k)+f(k+1,j)+w(i,j)}
朴素的解法是
Θ
(
N
3
)
\Theta(N^3)
Θ(N3),但它实际上可以被优化到
Θ
(
N
2
)
\Theta(N^2)
Θ(N2)
具体的优化需要推公式,不好直观理解,变化也不大,直接讲怎么用。
f
(
i
,
j
)
f(i,j)
f(i,j)如果满足四边形不等式,也就是
f
(
a
,
c
)
+
f
(
b
,
d
)
≤
f
(
a
,
d
)
+
f
(
b
,
c
)
f(a,c)+f(b,d)\le f(a,d)+f(b,c)
f(a,c)+f(b,d)≤f(a,d)+f(b,c)
(经常会以
f
(
a
,
c
)
+
f
(
b
,
d
)
=
f
(
a
,
d
)
+
f
(
b
,
c
)
f(a,c)+f(b,d)=f(a,d)+f(b,c)
f(a,c)+f(b,d)=f(a,d)+f(b,c)的形式出现)
(也可以是
w
(
i
,
j
)
w(i,j)
w(i,j)满足四边形不等式和单调性
w
(
b
,
c
)
≤
w
(
a
,
d
)
w(b,c)\le w(a,d)
w(b,c)≤w(a,d))
那么
k
k
k随
i
,
j
i,j
i,j单调递增。
记
s
(
i
,
j
)
s(i,j)
s(i,j)为
f
(
i
,
j
)
f(i,j)
f(i,j)取得最优解时候的
k
k
k。
那么
s
i
−
1
,
j
≤
s
i
,
j
≤
s
i
,
j
+
1
s_{i-1,j}\le s_{i,j}\le s_{i,j+1}
si−1,j≤si,j≤si,j+1
或者
s
i
,
j
−
1
≤
s
i
,
j
≤
s
i
+
1
,
j
s_{i,j-1}\le s_{i,j}\le s_{i+1,j}
si,j−1≤si,j≤si+1,j
用哪个式子取决于题目。比如这道题用第二个好写
可以用一个平面
i
O
j
iOj
iOj直观理解,就是左上低右下高这样
然后就可以优化枚举了。
照样是枚举
i
,
j
,
k
i,j,k
i,j,k,
k
k
k就是
s
i
,
j
s_{i,j}
si,j,从上面那个范围里面枚举。
虽然是三层循环不过实际上就是
Θ
(
N
2
)
\Theta(N^2)
Θ(N2)的
实际用起来不用搞什么证明四边形不等式还是证明单调性
写个
N
3
N^3
N3如果式子像像的,打个表看一下就好了
打表的时候要注意不要打那些冗余的状态,不然可能看不出来单调性
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cctype>
#include<cstring>
using namespace std;
#define reg register int
int P,Q;
int Lst[105]={};
int Sum[105]={};
int F[105][105]={};
int S[105][105]={};
int main()
{
scanf("%d%d",&P,&Q);
for(reg i=1;i<=Q;++i)scanf("%d",&Lst[i]);
sort(Lst+1,Lst+1+Q); Lst[++Q]=P+1;
memset(F,0x3f,sizeof(F));
for(reg i=1;i<=Q;++i)Sum[i]=Sum[i-1]+Lst[i]-Lst[i-1]-1;
for(reg i=1;i<=Q;++i)S[i][i]=i,F[i][i]=0;
for(reg j=2;j<=Q;++j)for(reg i=j-1;i;--i)
for(reg t,k=S[i][j-1];k<=S[i+1][j];++k)
{
t=F[i][k]+F[k+1][j]+Sum[j]-Sum[i-1]+j-i-1;
if(t<=F[i][j])F[i][j]=t,S[i][j]=k;
}
printf("%d",F[1][Q]);
return 0;
}