• [CF1149B] Three Religions


    Description

    给定长度为 (n) 的母串和三个子串 (s_1,s_2,s_3)。初始时子串均为空。

    (q) 次询问。你需要支持两种操作:向某个子串末尾添加一个字母,或者删去某个子串末尾的字母。

    在每次操作后,你需要回答,是否能从母串中分离出三个不相交的子序列,满足这三个子序列恰好是 (s_1,s_2,s_3)

    在任意时刻,(s_1,s_2,s_3) 的长度均不会超过 (250)

    (1 le n le 10^5) , (1le q le 10^3)

    Solution

    (f[i][j][k]) 表示三个子串分别匹配到了第 (i,j,k) 个字符,在母串中推进的最短距离

    (g[i][c]) 表示 (S[i..n]) 内字符 (c) 第一次出现的位置

    [f[i][j][k]=left{ egin{aligned} & g[f[i-1][j][k]+1][s_1[i]] \ & g[f[i][j-1][k]+1][s_2[j]] \ & g[f[i][j][k-1]+1][s_3[k]] end{aligned} ight. ]

    初始条件 (f[0][0][0]=0),其余初值设为 (+infty)

    对于插入操作,暴力计算即可,每次 (O(l^2))

    对于删除操作,减小串长即可

    对于询问,比较 (f[l_1][l_2][l_3]) 是否 (le n) 即可

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 100005;
    
    char s[N],s1[N],s2[N],s3[N];
    int n,l1,l2,l3,q,id,g[N][26],f[255][255][255];
    char op,tmp;
    
    void presolve()
    {
        for(int i=0;i<26;i++)
        {
            int ch='a'+i;
    
            vector <int> vec;
            for(int j=1;j<=n;j++) if(s[j]==ch) vec.push_back(j);
    
            int pos=1;
            for(auto now:vec)
            {
                for(int j=pos;j<=now;j++) g[j][i]=now;
                pos=now+1;
            }
            for(int j=pos;j<=n+2;j++) g[j][i]=n+1;
        }
    }
    
    void dp1(int i)
    {
        for(int j=0;j<=l2;j++)
        {
            for(int k=0;k<=l3;k++)
            {
                int tmp=1e9;
                if(i) tmp=min(tmp, g[f[i-1][j][k]+1][s1[i]-'a']);
                if(j) tmp=min(tmp, g[f[i][j-1][k]+1][s2[j]-'a']);
                if(k) tmp=min(tmp, g[f[i][j][k-1]+1][s3[k]-'a']);
                f[i][j][k]=tmp;
            }
        }
    }
    
    void dp2(int j)
    {
        for(int i=0;i<=l1;i++)
        {
            for(int k=0;k<=l3;k++)
            {
                int tmp=1e9;
                if(i) tmp=min(tmp, g[f[i-1][j][k]+1][s1[i]-'a']);
                if(j) tmp=min(tmp, g[f[i][j-1][k]+1][s2[j]-'a']);
                if(k) tmp=min(tmp, g[f[i][j][k-1]+1][s3[k]-'a']);
                f[i][j][k]=tmp;
            }
        }
    }
    
    void dp3(int k)
    {
        for(int i=0;i<=l1;i++)
        {
            for(int j=0;j<=l2;j++)
            {
                int tmp=1e9;
                if(i) tmp=min(tmp, g[f[i-1][j][k]+1][s1[i]-'a']);
                if(j) tmp=min(tmp, g[f[i][j-1][k]+1][s2[j]-'a']);
                if(k) tmp=min(tmp, g[f[i][j][k-1]+1][s3[k]-'a']);
                f[i][j][k]=tmp;
            }
        }
    }
    
    void cl1(int i)
    {
        for(int j=0;j<=l2;j++)
        {
            for(int k=0;k<=l3;k++)
            {
                f[i][j][k]=n+1;
            }
        }
    }
    
    void cl2(int j)
    {
        for(int i=0;i<=l1;i++)
        {
            for(int k=0;k<=l3;k++)
            {
                f[i][j][k]=n+1;
            }
        }
    }
    
    void cl3(int k)
    {
        for(int i=0;i<=l1;i++)
        {
            for(int j=0;j<=l2;j++)
            {
                f[i][j][k]=n+1;
            }
        }
    }
    
    signed main()
    {
        ios::sync_with_stdio(false);
    
        cin>>n>>q>>s+1;
    
        for(int i=0;i<=254;i++)
        {
            for(int j=0;j<=254;j++)
            {
                for(int k=0;k<=254;k++)
                {
                    f[i][j][k]=n+1;
                }
            }
        }
    
        presolve();
    
        f[0][0][0]=0;
    
        for(int i=1;i<=q;i++)
        {
            cin>>op;
            if(op=='+')
            {
                cin>>id>>tmp;
                if(id==1) s1[++l1]=tmp, dp1(l1);
                if(id==2) s2[++l2]=tmp, dp2(l2);
                if(id==3) s3[++l3]=tmp, dp3(l3);
            }
            else
            {
                cin>>id;
                if(id==1) cl1(l1), --l1;
                if(id==2) cl2(l2), --l2;
                if(id==3) cl3(l3), --l3;
            }
            cout<<(f[l1][l2][l3]<=n ? "YES" : "NO")<<endl;
        }
    }
    
    
  • 相关阅读:
    CommonJs、AMD、CMD模块化规范
    在 repeater控件中有button控件,如何点击button按钮在后头产生方法
    DropdownList动态绑定数据库中的字段
    电脑操作的快捷键
    多条件查询
    asp.Net_图片上传的一个类库的源码
    日期转换_中文To数字
    VS2010断点设置技巧
    附加进程调试
    电脑常用的几个快捷键
  • 原文地址:https://www.cnblogs.com/mollnn/p/13329716.html
Copyright © 2020-2023  润新知