牛客OI周赛8-普及组 兔子的名字(子序列自动机)&&牛客练习赛51 B题 子串查询

链接:https://ac.nowcoder.com/acm/contest/543/B

子序列自动机:,对于abcacd,建立一个dis[ max ][ n ],如果dis[ i ][ j ]为-1,说明ascii值为'a'+j的字符在>=i之后不存在,如果为b,说明ascii值为'a'+j的字符在>=i之后最近的位置为 b

之后:

            int tmp=0,flag=1;
            for(int len1=0;len1<len;len1++)
            {
                char sim=si[m1][len1];
                if(dis[n1][tmp][sim-'A']==-1)
                {
                    flag=0;
                    break;
                }
                tmp=dis[n1][tmp][sim-'A'];
             }

只需要子序列的复杂度就可以判断这个串是否是母串的子序列

AC代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<cmath>
#include<stack>
#include<map>
#include<set>
using namespace std;
#define LL long long
const int MOD=100000007;
const int inf=0x3f3f3f3f;
const LL inff=0x3f3f3f3f3f3f3f3f;
const LL N=20000005;
const LL M=50005;
#define MEF(x) memset(x,-1,sizeof(x))
#define ME0(x) memset(x,0,sizeof(x))
#define MEI(x) memset(x,inf,sizeof(x))
char ti[1005][105];
char si[1005][105];
int dis[1005][105][100];
int al[100];
int main()
{
    int n,m;
    cin>>n>>m;
    for(int n1=1;n1<=n;n1++)
    {
        cin>>ti[n1];
    }
    for(int m1=1;m1<=m;m1++)
    {
        cin>>si[m1];
    }
    for(int n1=1;n1<=n;n1++)
    {
        MEF(al);
        int len=strlen(ti[n1]);
        for(int len1=len;len1>=0;len1--)
        {
            for(int i=0;i<58;i++)
            {
                dis[n1][len1][i]=al[i];
            }
            if(len1>0)
            {
                al[ti[n1][len1-1]-'A']=len1;
            }
        }
    }
    for(int n1=1;n1<=n;n1++)
    {
        int ans=0;
        for(int m1=1;m1<=m;m1++)
        {
            int len=strlen(si[m1]);
            int tmp=0,flag=1;
            for(int len1=0;len1<len;len1++)
            {
                char sim=si[m1][len1];
                if(dis[n1][tmp][sim-'A']==-1)
                {
                    flag=0;
                    break;
                }
                tmp=dis[n1][tmp][sim-'A'];
            }
            if(flag)
            {
                ans++;
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

子串查询:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<vector>
#include<cmath>
#include<stack>
#include<map>
#include<set>
using namespace std;
#define LL long long
const int MOD=100000007;
const int inf=0x3f3f3f3f;
const LL inff=0x3f3f3f3f3f3f3f3f;
const LL N=15;
const LL M=15;
#define MEF(x) memset(x,-1,sizeof(x))
#define ME0(x) memset(x,0,sizeof(x))
#define MEI(x) memset(x,inf,sizeof(x))
int dis[100005][30],al[100005];
int main()
{
    ios::sync_with_stdio(false);
    int n,m;
    cin>>n>>m;
    char s[100005];
    cin>>s+1;
    MEF(al);
    for(int i=n;i>=0;i--)
    {
        for(int j=0;j<26;j++)
        {
            dis[i][j]=al[j];
        }
        if(i>0)
        {
            al[s[i]-'a']=i;
        }
    }
    for(int m1=1;m1<=m;m1++)
    {
        string a;
        cin>>a;
        int tmp=0,flag=1;
        for(int i=0;i<a.size();i++)
        {
            if(dis[tmp][a[i]-'a']==-1)
            {
                flag=0;
                break;
            }
            tmp=dis[tmp][a[i]-'a'];
        }
        if(flag)
        {
            cout<<"YES"<<endl;
        }
        else
        {
            cout<<"NO"<<endl;
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值