zoj3228文字列の検索[kuangbin topic-ac automata]

この質問では、ACオートマトンのさらなる使用について検討します。acオートマトンをパターンマッチングに使用する場合、パターン文字列の最後の文字に対応するノードに到達したかどうかに基づいて、それが出現するかどうかが判断されるため、パターン文字列を重複させることができます。ただし、この質問には新しい要件があり、入力データは文字列が重複できるかどうかを指定するため、重複があるかどうかを判断するために、各文字列の位置を最後に保存する必要もあります。
ここで注意すべき点は、同じ文字列の2つの異なるクエリが存在する可能性があることです。1つのクエリが重複し、1つは重複しません。したがって、挿入時にこの状況に対処し、文字列の2番目の出現をマークして、追加する必要がありますそのIDは、最初に表示されたときに指定されたIDに割り当てられます。

#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <queue>
#include <map>
#include <cstring>
#define fi first
#define se second
#define FIN freopen("in.txt","r",stdin)
#define FIO freopen("out.txt","w",stdout)
#define INF 0x3f3f3f3f
#define per(i,a,n) for(int i = a;i < n;i++)
#define rep(i,a,n) for(int i = n;i > a;i--)
#define pern(i,a,n) for(int i = a;i <= n;i++)
#define repn(i,a,n) for(int i = n;i >= a;i--)
#define fastio std::ios::sync_with_stdio(false)
#define all(a) a.begin(), a.end()
#define ll long long
#define pb push_back
#define endl "\n"
#define pii pair<int,int>
#define sc(n) scanf("%d", &n)
#define CASET int ___T; scanf("%d", &___T); for(int cs=1;cs<=___T;cs++)
template<typename T> inline void _max(T &a,const T b){
    
    if(a<b) a = b;}
template<typename T> inline void _min(T &a,const T b){
    
    if(a>b) a = b;}
using namespace std;
//inline ll read(){
    
    
//    ll a=0;int f=0;char p=getchar();
//    while(!isdigit(p)){f|=p=='-';p=getchar();}
//    while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=getchar();}
//    return f?-a:a;
//}

const int maxn = 100000*6+100;

const int maxnode = 26;



int ch[maxn][maxnode]; //字典树
int cnt[maxn];    //单词出现次数
int sz;
int fail[maxn];
int last[100000+100];
char s[100000+100];
int ty[100000+100];
char ss[100000+100][10];
int vis[100000+100];
int ans[100000+100][2];
void init()
{
    
    

    sz = 1;
    memset(ch[0], 0, sizeof(ch[0]));
    memset(cnt,0,sizeof(cnt));
    //memset(ty,0,sizeof(ty));
    memset(last,-1,sizeof(last));
    memset(vis,0,sizeof(vis));
    memset(ans,0,sizeof(ans));
    cnt[0] = 0;
}
void insert(char str[], int len,int id) //插入字符串
{
    
    
    int u = 0;
    per(i, 0, len)
    {
    
    
        int v = str[i]-'a';
        if (!ch[u][v])
        {
    
    
            memset(ch[sz], 0, sizeof(ch[sz]));
            cnt[sz] = 0;
            ch[u][v] = sz++;
        }
        u = ch[u][v];
    }
    if(cnt[u] == 0)cnt[u] = id;
    else vis[id] = cnt[u];
    //在这里我们可以建立一个int-string的映射,以通过节点序号得知这个点是哪个单词的结尾
}

void getfail()
{
    
    
    //所有模式串已插入完成
    queue<int> q;
    per(i, 0,maxnode)
    {
    
    
        if (ch[0][i])
        {
    
    
            fail[ch[0][i]] = 0;
            q.push(ch[0][i]);
        }
    }
    while (!q.empty())
    {
    
    
        int now = q.front();
        q.pop();
        per(i, 0,  maxnode)
        {
    
    
            if (ch[now][i])
            {
    
    
                fail[ch[now][i]] = ch[fail[now]][i];
                q.push(ch[now][i]);
            }
            else
                ch[now][i] = ch[fail[now]][i];
        }
        //cnt[now] |= cnt[fail[now]];
    }
}
int n;
void query()
{
    
    
    int now = 0;
    int len = strlen(s);
    per(i,0,len)
    {
    
    
        now = ch[now][s[i]-'a'];
        int j = now;
        while(j)
        {
    
    
            if(cnt[j]){
    
    
                ans[cnt[j]][0]++;
                int dis = i-last[cnt[j]];
                if(dis>=strlen(ss[cnt[j]])){
    
    
                    ans[cnt[j]][1]++;
                    last[cnt[j]] = i;
                }
            }
            j = fail[j];
        }
    }
}

int main()
{
    
    

    #ifndef ONLINE_JUDGE
        int startTime = clock();
        FIN;
    #endif
    //fastio;
	//忘记初始化是小狗
    //freopen("out.txt","w",stdout);
    //ios::sync_with_stdio(false);
    int T = 0;
    while(~scanf("%s",s))
    {
    
    
        init();
        sc(n);
        pern(i,1,n)
        {
    
    
            scanf("%d%s",&ty[i],&ss[i]);
            insert(ss[i],strlen(ss[i]),i);
        }
        getfail();
        query();
        printf("Case %d\n", ++T);
        pern(i,1,n)
        {
    
    
            if(!vis[i]) printf("%d\n",ans[i][ty[i]]);
            else printf("%d\n",ans[vis[i]][ty[i]]);
        }
        printf("\n");
    }
    #ifndef ONLINE_JUDGE
        printf("\nTime = %dms\n", clock() - startTime);
    #endif
    return 0;
}

おすすめ

転載: blog.csdn.net/qq_39586345/article/details/108567382