The 2019 Asia Nanchang First Round Online Programming Contest C. Hello 2019(动态dp)

题意:要找到一个字符串里面存在子序列9102 而不存在8102 输出最小修改次数

思路:对于单次询问 我们可以直接区间dpOn求出最小修改次数 但是对于多次询问 我在大部分题解看到的解释一般是用线段树维护每一个区间段 每一个区间上挂一个dp[5][5]的矩阵 表示从i状态转移到j状态索要的最小修改次数 转移的时候就可以像区间dp一样 通过两个子区间合并 跟新答案。

#include <bits/stdc++.h>
using namespace std;
const double pi = acos(-1.0);
const int N = 2e5+7;
const int inf = 0x3f3f3f3f;
const double eps = 1e-6;
typedef long long ll;
const ll mod = 10007;
char s[N];
struct tree{
    int dp[5][5];
}t[N<<2];
int L[N<<2],R[N<<2];
tree mul(tree a,tree b){
    tree tmp;
    memset(tmp.dp,inf,sizeof(tmp.dp));
    for(int i=0;i<5;i++)
        for(int j=0;j<5;j++)
            for(int k=0;k<5;k++)
                tmp.dp[i][j]=min(tmp.dp[i][j],a.dp[i][k]+b.dp[k][j]);
    return tmp;
}
void build(int p,int l,int r){
    L[p]=l; R[p]=r;
//    memset(t[p].dp,inf,sizeof(t[p].dp));
    if(l==r){
        memset(t[p].dp,inf,sizeof(t[p].dp));
        for(int i=0;i<5;i++) t[p].dp[i][i]=0;
        if(s[l]=='2'){
            t[p].dp[0][0]=1; t[p].dp[0][1]=0;
        }else if(s[l]=='0'){
            t[p].dp[1][1]=1; t[p].dp[1][2]=0;
        }else if(s[l]=='1'){
            t[p].dp[2][2]=1; t[p].dp[2][3]=0;
        }else if(s[l]=='9'){
            t[p].dp[3][3]=1; t[p].dp[3][4]=0;
        }else if(s[l]=='8'){
            t[p].dp[3][3]=1; t[p].dp[4][4]=1;
        }
        return ;
    }
    int mid=(l+r)>>1;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
    t[p]=mul(t[p<<1],t[p<<1|1]);
}
tree query(int p,int l,int r){
    if(l<=L[p]&&R[p]<=r){
        return t[p];
    }
    int mid=(L[p]+R[p])>>1;
    tree ans1,ans2;
    memset(ans1.dp,inf,sizeof(ans1.dp));
    memset(ans2.dp,inf,sizeof(ans2.dp));
    if(r<=mid) return query(p<<1,l,r);
    if(l>mid) return query(p<<1|1,l,r);
    return mul(query(p<<1,l,r),query(p<<1|1,l,r));
}
int main(){
//    ios::sync_with_stdio(false);
//    cin.tie(0); cout.tie(0);
    int n,Q; scanf("%d%d",&n,&Q);
    scanf("%s",s+1);
    reverse(s+1,s+1+n);
//    printf("%s
",s+1);
    build(1,1,n);
//    cout<<t[1].dp[0][4]<<endl;
    for(int i=1;i<=Q;i++){
        int l,r; scanf("%d%d",&l,&r);
//        cout<<n-r+1<<" "<<n-l+1<<endl;
        tree ans=query(1,n-r+1,n-l+1);
        printf("%d
",ans.dp[0][4]==inf?-1:ans.dp[0][4]);
    }
}
View Code
原文地址:https://www.cnblogs.com/wmj6/p/11495421.html