codeforces#1150D. Three Religions(dp+序列自动机)

题目链接:

https://codeforces.com/contest/1150/problem/D

题意:

 给出长度为$n$的字符串,和$q$次询问

每次询问是,给$x$宗教增加一个字符$key$,或者让$x$宗教的字符串长度减一

问是否给原字符串染色,每个字符只能染上一种颜色,把相同颜色字符串按顺序取出刚好是每个宗教的字符串

数据范围:

$1 \leq n \leq 100\,000$
$1 \leq q \leq 1000$

分析: 

定义状态$DP[x][y][z]$,为考虑1号宗教字符串长度$x$,考虑2号宗教字符串长度$y$,考虑3号宗教字符串长度$z$,给它们匹配需要的最短原字符串

$DP[x][y][z]=min(nex[DP[x-1][y][z]+1]],nex[DP[x][y-1][z]+1]],nex[DP[x][y][z-1]+1]])$

具体看代码

ac代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int maxm=250+10;
int len[maxm][4],top[4];
int word[maxn],nex[maxn][30];
int dp[maxm][maxm][maxm];
int main()
{
    int n,q;
    scanf("%d %d",&n,&q);
    getchar();
    for(int i=1;i<=n;i++)
    {
        char key;
        scanf("%c",&key);
        word[i]=key-'a';
    }
    for(int i=0;i<30;i++)
        nex[n+1][i]=nex[n+2][i]=n+1;
    for(int i=n;i>=1;i--)
    {
        for(int j=0;j<30;j++)
            nex[i][j]=nex[i+1][j];
        nex[i][word[i]]=i;
    }
    for(int i=0;i<30;i++)nex[0][i]=nex[1][i];
    while(q--)
    {
        getchar();
        char comd;
        scanf("%c",&comd);
        if(comd=='+')
        {
            char key;
            int t,x;
            scanf("%d %c",&t,&key);
            x=key-'a';
            len[++top[t]][t]=x;
            for(int i=(t==1?top[1]:0);i<=top[1];i++)
                for(int j=(t==2?top[2]:0);j<=top[2];j++)
                    for(int k=(t==3?top[3]:0);k<=top[3];k++)
                        dp[i][j][k]=n+1;
            dp[0][0][0]=0;
            for(int i=(t==1?top[1]:0);i<=top[1];i++)
                for(int j=(t==2?top[2]:0);j<=top[2];j++)
                    for(int k=(t==3?top[3]:0);k<=top[3];k++)
                    {
//                        cout<<i<<" "<<j<<" "<<k<<endl;
//                         cout<<dp[i][j][k]<<endl;
                        if(i!=0)
                            dp[i][j][k]=min(dp[i][j][k],nex[dp[i-1][j][k]+1][len[i][1]]);
                        if(j!=0)
                            dp[i][j][k]=min(dp[i][j][k],nex[dp[i][j-1][k]+1][len[j][2]]);
                        if(k!=0)
                            dp[i][j][k]=min(dp[i][j][k],nex[dp[i][j][k-1]+1][len[k][3]]);
                    }
        }
        else
        {
            int t;
            scanf("%d",&t);
            top[t]--;
        }
       // cout<<dp[top[1]][top[2]][top[3]]<<endl;
        if(dp[top[1]][top[2]][top[3]]<=n)printf("YES\n");
        else printf("NO\n");
    }

    return 0;
}

  

 

posted @ 2019-05-01 21:42  czh~  阅读(281)  评论(0编辑  收藏  举报