【牛客小白赛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<bits/stdc++.h>
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 <bits/stdc++.h>
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;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值