[Luogu1622] 释放囚犯 [四边形不等式][区间dp]

题目链接

很显然可以把这个过程反过来计算贡献。
所以这就是道石子合并。
顺便打一下四边形不等式。


四边形不等式

论文

对于方程形式如下的一类 2 D / 1 D 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)\}
朴素的解法是 Θ ( N 3 ) \Theta(N^3) ,但它实际上可以被优化到 Θ ( N 2 ) \Theta(N^2)
具体的优化需要推公式,不好直观理解,变化也不大,直接讲怎么用。

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) 的形式出现)
(也可以是 w ( i , j ) w(i,j) 满足四边形不等式和单调性 w ( b , c ) w ( a , d ) w(b,c)\le w(a,d)
那么 k k i , j i,j 单调递增。
s ( i , j ) s(i,j) f ( i , j ) f(i,j) 取得最优解时候的 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}
或者 s i , j 1 s i , j s i + 1 , j s_{i,j-1}\le s_{i,j}\le s_{i+1,j}
用哪个式子取决于题目。比如这道题用第二个好写
可以用一个平面 i O j iOj 直观理解,就是左上低右下高这样

然后就可以优化枚举了。
照样是枚举 i , j , k i,j,k k k 就是 s i , j s_{i,j} ,从上面那个范围里面枚举。
虽然是三层循环不过实际上就是 Θ ( N 2 ) \Theta(N^2)

实际用起来不用搞什么证明四边形不等式还是证明单调性
写个 N 3 N^3 如果式子像像的,打个表看一下就好了
打表的时候要注意不要打那些冗余的状态,不然可能看不出来单调性


#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;
}

猜你喜欢

转载自blog.csdn.net/Estia_/article/details/83057293