E. New Year and Old Subsequence(線段樹+DP)

傳送門

題意:在s[l~r]中減少最少的字符數,使得得到的字符串含有2017子序列,不含2016子序列。一共q次查詢。

思路:設狀態0表示空串,狀態1表示走到了狀態”2”,狀態2表示都到了”20”,狀態3表示走到”201”,狀態4表示走到”2017”。
設f[i,j]表示在走到該區間之前走到了狀態i,且在走完該區間後走到了狀態j,最少需要刪掉多少個字符。
如果知道左右區間的狀態的話這兩個矩陣顯然是可以合併的。
那麼只要用線段樹來維護這個dp的轉移即可。

 

#include<cstdio>
#include<algorithm>
using namespace std;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int N=200005;
char s[N];
struct node
{
    int mat[5][5];
    node operator + (node x)
    {
        node ans;
        for(int i=0;i<5;i++)
        {
            for(int j=0;j<5;j++)
            {
                ans.mat[i][j]=N;
                for(int k=0;k<5;k++)
                {
                    ans.mat[i][j]=min(ans.mat[i][j],mat[i][k]+x.mat[k][j]);
                }
            }
        }
        return ans;
    }
}a[N<<2];
void build(int l,int r,int rt)
{
    if(l==r)
    {
        for(int i=0;i<5;i++)
        {
            for(int j=0;j<5;j++)
            {
                a[rt].mat[i][j]=(i==j)?0:N;
            }
        }
        if(s[l]=='2')
            a[rt].mat[0][1]=0,a[rt].mat[0][0]=1;
        if(s[l]=='0')
            a[rt].mat[1][2]=0,a[rt].mat[1][1]=1;
        if(s[l]=='1')
            a[rt].mat[2][3]=0,a[rt].mat[2][2]=1;
        if(s[l]=='7')
            a[rt].mat[3][4]=0,a[rt].mat[3][3]=1;
        if(s[l]=='6')
            a[rt].mat[3][3]=1,a[rt].mat[4][4]=1;
        return;
    }
    int mid=(l+r)/2;
    build(lson);
    build(rson);
    a[rt]=a[rt<<1]+a[rt<<1|1];
}
node query(int l,int r,int L,int R,int rt)
{
    if(L<=l&&r<=R)
        return a[rt];
    int m=(l+r)/2;
    if(m<L)
        return query(m+1,r,L,R,rt<<1|1);
    if(m>=R)
        return query(l,m,L,R,rt<<1);
    return query(l,m,L,R,rt<<1)+query(m+1,r,L,R,rt<<1|1);
}
int main()
{
    int n,q;
    while(~scanf("%d%d%s",&n,&q,s+1))
    {
        build(1,n,1);
        while(q--)
        {
            int l,r;
            scanf("%d%d",&l,&r);
            int ans=query(1,n,l,r,1).mat[0][4];
            if(ans==N)
                ans=-1;
            printf("%d\n",ans);
        }
    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章