【牛客小白赛12:J/2019南昌网络赛:M/牛客练习赛23:D】查询字符串ss是否是字符串s的子序列(序列自动机裸题)

 牛客小白赛12:J 地址:https://ac.nowcoder.com/acm/contest/392/J

2019南昌网络赛:M 地址:https://nanti.jisuanke.com/t/38232

牛客练习赛23:D 地址:https://ac.nowcoder.com/acm/contest/156/D

题目:


给定一个字符串s,和n个字符串ss,查询每个ss是不是s的子序列

 

解题思路:


序列自动机,纯裸题,套模版。

序列自动机的nxt[][]数组, nxt[i][j]表示下标i后面第一个j+'a'出现的位置,倒序求这个数组,求法见代码

之所以称之为序列自动机大概就是因为通过这个方法可以求出原串的所有子序列吧。

时间复杂度:n为s的长度,获得nxt数组O(26*n),查询O(\Sigma |ss|), 所以总的时间复杂度 O(26*n+\Sigma |ss|)

一定要判断ss[0]是否出现了,否则会出现段错误,[-1]

ac代码: 


前两道题:

#include
using namespace std;
#define lowbit(x) ((x)&(-x))
typedef long long ll;
const int maxn = 1000006;
string s, qs;
int n;
int nxt[maxn][30],pos[30];//nxt[i][j]表示i后面出现的第一个j+'a'的下标,pos[i]记录i+'a'目前为止出现的最靠左的位置
void getNxt()
{
    int len = s.length();
    memset(pos, -1, sizeof(pos));
    for(int i = len - 1; i >= 0; i--)//倒序!!
    {
        for(int j = 0; j < 26; j++)
            nxt[i][j] = pos[j];
        pos[s[i] - 'a'] = i;//更新pos
    }
}
int main()
{
    //freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    getline(cin, s);
    getNxt();
    cin >> n;
    while(n--)
    {
        cin >> qs;
        if(pos[qs[0] - 'a'] == -1)
            printf("No\n");
        else
        {
            int now = pos[qs[0] - 'a'];//s[0]第一次出现的位置
            int len = qs.length(), i;
            for(i = 1; i < len; i++)
            {
                now = nxt[now][qs[i] - 'a'];//前一个字符后面有没有下一个字符
                if(now == -1)
                {
                    printf("No\n");
                    break;
                }
            }
            if(i == len) printf("Yes\n");
        }
    }

    return 0;
}

 牛客练习23:D 仔细读题啊!!仔细看样例!!我一直以为某个排列出现多次的话就会产生多点伤害值!!其实都只产生1点,浪费了好长时间(;´༎ຶД༎ຶ`)

//abcdefghi 9
#include 
using namespace std;
typedef long long ll;
const int maxn = 3005;
string s;
int nxt[maxn][10], pos[10], a[]={0,1,2,3,4,5,6,7,8};
ll ans = 0;
void getNxt()
{
    memset(pos, -1, sizeof(pos));
    int len = s.length();
    for(int i = len - 1; i >= 0; i--)
    {
        for(int j = 0; j <= 8; j++)
            nxt[i][j] = pos[j];
        pos[s[i] - 'a'] = i;
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin >> s;
    getNxt();
    do{
        int now = pos[a[0]], i = 0 ;//a[0]最先出现的位置
        if(now == -1) continue;//如果排列的第一个字母没有出现过
        for(i = 1; i < 9;i++)
        {
            now = nxt[now][a[i]];
            if(now == -1) break;
        }
        if(i == 9) ans++;//是s的子串
    }while(next_permutation(a,a+9));
    cout << ans << endl;;
    return 0;
}

 

你可能感兴趣的:(字符串专题,序列自动机)