连续段DP

更新日志

概念

这个DP主要用于解决类似于“在一个数列中产生一个个连续块,求可能数”的动规问题。

比如,在一排连续的盒子中放苹果,连着的苹果都可视作一个连续块。

思路

一般来说,我们都会考虑新加入的元素对原状态的影响。通常的,有三种情况:

  • 加入的元素在原先某个连续段的两端。
  • 加入的元素单独成为一个连续段。
  • 加入的元素把两个连续段连成了一个。

值得注意的是,通常不考虑连续段的具体状态,而只考虑整体状态,如连续块数量与元素数量。

究其原因,是因为\(存在即合理\)

更具体地,之所以如此,是因为当前情况必然由之前情况转移而来,而非转移到下一个情况去,所以无需担心这种情况会不会发生的疑问。

只要存在合法的上一种情况,这种情况就必然可以存在。(当然前提是状态转移方程没错哈哈哈)

只要这种情况不合法,那么就不可能存在合法的上一种情况,或者说不可能从不可能的方式转移过来。(举例子:无需担心情况二插入空间不够的问题,或者由方法一转移来但是事实上合并了两个连续段的情况。)

公式

\(f_{i,j}\)表示有\(i\)个元素,\(j\)个连续块的情况

\[f_{i,j}= \begin{cases} 2j·f_{i-1,j} \\ j·f_{i-1,j-1} \\ (j-1)·f_{i-1,j+1}\\ \end{cases} \]

三种情况分别对应思路部分中三种。

细节讲解:

  • 情况一之所以要\(×2j\),是因为有\(j\)个连续段可供选择,每一个都可以选择两段之一。
  • 情况二\(×j\),是因为有\(j\)个空隙可以插入新的连续段。
  • 情况三同情况二类似,但是不能插入到两端的空隙中,只能插到两个连续段中间。

例题

不死鸟与电脑

代码

前注:非题解,不做详细讲解

#include<bits/stdc++.h>
using namespace std;

#define fir first
#define sec second
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,int> pli;
typedef pair<int,ll> pil;
typedef pair<ll,ll> pll;
typedef pair<int,pii> pip;
typedef vector<int> veci;
typedef vector<pii> vecp;
typedef priority_queue<int> bghp;
typedef priority_queue<int,vector<int>,greater<int> > lthp;
typedef priority_queue<pli,vector<pli>,greater<pli> > prhp;

const int mod=998244353;
const int N=1e4+5;

int n,m,k;
int r[N],c[N];
veci rs[N],cs[N];
vecp ed[N];
bool pd;

int dis[N];
bool vis[N];
void dij(){
    prhp pq;
    memset(dis,0x3f,sizeof(dis));
    dis[1]=0;
    pq.push({0,1});
    while(!pq.empty()){
        pli tp=pq.top();pq.pop();
        int now=tp.sec;
        if(vis[now])continue;
        vis[now]=true;
        for(int nxt=1;nxt<=k;nxt++){
            if(vis[nxt])continue;
            if((r[now]==r[nxt]&&abs(c[now]-c[nxt])==1||c[now]==c[nxt]&&abs(r[now]-r[nxt])==1)){
                if(dis[nxt]>dis[now]){
                    dis[nxt]=dis[now];
                    pq.push({dis[nxt],nxt});
                }
            }
            else if(abs(c[now]-c[nxt])<=2||abs(r[now]-r[nxt])<=2){
                if(dis[nxt]>dis[now]+1){
                    dis[nxt]=dis[now]+1;
                    pq.push({dis[nxt],nxt});
                }
            }
        }
    }
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    cin>>n>>m>>k;
    int en;
    for(int i=1;i<=k;i++){
        cin>>r[i]>>c[i];
        if(r[i]==n&&c[i]==m){
            pd=true;
            en=i;
        }
    }
    dij();
    if(!pd){
        en=k+1;
        for(int i=1;i<=k;i++){
            if(n-r[i]<=1||m-c[i]<=1)dis[en]=min(dis[en],dis[i]+1);
        }
    }
    if(dis[en]==0x3f3f3f3f)cout<<-1;
    else cout<<dis[en];
    return 0;
}
posted @ 2024-10-15 22:36  HarlemBlog  阅读(4)  评论(0编辑  收藏  举报