• HDU #5507 GT and Strings


    这是AC自动机系列的第一篇

    传送门

               Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)0

    大意

    给出N个仅由小写字母组成的字符串S[1]...S[N],它们的总长度为L。有Q组询问,询问分两类:

    1.S[x]是否是S[y]的子序列;

    2.S[x]是否是S[y]的子串。

    数据范围:

    N,L,Q<=100000,有60%的数据满足 L<=100, Q<=1000


    Solution

    先贴代码,留坑待填。
    开始填坑。
    首先由于这题的数据范围比较坑,不大可能开二维数组来存字符串,故采用了将各字符串连续存起来的办法,另开一个数组记录各串首字母位置。
    void input(int n){
        for(int i=0; i<n; i++){
            scanf("%s", s+beg[i]);
            beg[i+1]=beg[i]+strlen(s+beg[i]); 
        }
    }
    判断子序列询问比较简单,可以O(N)解决。
    nt[i][j]表示位置第j个字母在位置i之后(包括位置i)首次出现的位置。从后往前扫一遍就可以打出这个表了。
    int nt[N][26];
    void calc_nt(int n){
        memset(nt, -1, 26*beg[n]<<2);
        for(int i=0, j; i<n; i++){
            j=beg[i+1]-1;
            nt[j][s[j]-'a']=j;
            for(j--; j>=beg[i]; j--)
                for(int k=0; k<26; k++)
                    if(k==s[j]-'a') nt[j][k]=j;
                    else nt[j][k]=nt[j+1][k];
        }
    }

    查询时只要在串S[j]对应的nt表中不断往后匹配就可以了:

    int subseq(int x, int y){
        if(len(x)>len(y)) return 0;
        for(int i=beg[x], j=beg[y]; i<beg[x+1]; i++){
            if(j>=beg[y+1]) return 0;
            if(nt[j][s[i]-'a']==-1) return 0;
            j=nt[j][s[i]-'a']+1;
        }
        return 1;
    }

    判断子串的询问可用AC自动机离线处理。

    AC代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N(1e5+5);
    int beg[N], id[N];
    char s[N];
    
    void input(int n){
        for(int i=0; i<n; i++){
            scanf("%s", s+beg[i]);
            beg[i+1]=beg[i]+strlen(s+beg[i]); 
        }
    }
    
    int x[N], y[N];
    void preprocess(int q, map<pair<int,int>,int> &mp){
        mp.clear();
        for(int i=0; i<q; i++){
            scanf("%d%d", x+i, y+i), x[i]--, y[i]--;
            mp[{id[x[i]], id[y[i]]}];
        }
    }
    
    int nt[N][26];
    void calc_nt(int n){
        memset(nt, -1, 26*beg[n]<<2);
        for(int i=0, j; i<n; i++){
            j=beg[i+1]-1;
            nt[j][s[j]-'a']=j;
            for(j--; j>=beg[i]; j--)
                for(int k=0; k<26; k++)
                    if(k==s[j]-'a') nt[j][k]=j;
                    else nt[j][k]=nt[j+1][k];
        }
    }
    
    int len(int x){return beg[x+1]-beg[x];}
    
    int subseq(int x, int y){
        if(len(x)>len(y)) return 0;
        for(int i=beg[x], j=beg[y]; i<beg[x+1]; i++){
            if(j>=beg[y+1]) return 0;
            if(nt[j][s[i]-'a']==-1) return 0;
            j=nt[j][s[i]-'a']+1;
        }
        return 1;
    }
    
    void solve1(int q, map<pair<int,int>,int> &mp, int *ans){
        mp.clear();
        for(int i=0; i<q; i++){
            if(mp.find({x[i], y[i]})==mp.end())
                mp[{x[i], y[i]}]=subseq(x[i], y[i]);
            ans[i]=mp[{x[i], y[i]}];
        }
    }
    
    int ch[N][26], f[N], last[N], val[N];
    void init(int i){
        memset(ch[i], 0, sizeof(ch[i]));
        f[i]=last[i]=val[i]=0;
    }
    
    void build_trie(int n){
        int tot=0; init(tot++);
        for(int i=0, ID=0, u; i<n; i++){
            for(int j=(u=0,beg[i]); j<beg[i+1]; j++){
                int &v=ch[u][s[j]-'a'];
                if(!v) v=tot++, init(v);
                u=v;
            }
            if(!val[u]) val[u]=++ID;
            id[i]=val[u];
        }
    }
    
    int que[N];
    int build_ac(){
        int head=0, tail=0;
        for(int i=0; i<26; i++){
            if(ch[0][i]) que[tail++]=ch[0][i];
        }
        for(int u; head!=tail;){
            u=que[head++];
            for(int i=0; i<26; i++){
                int &v=ch[u][i];
                if(v){
                    f[v]=ch[f[u]][i];
                    last[v] = val[f[v]] ? f[v] : last[f[v]];
                    que[tail++]=v;
                 }
                else v=ch[f[u]][i];
            }
        }
    }
    
    void solve2(int n, int q, map<pair<int,int>,int> &mp, int *ans){
        for(int i=0, x, y; i<n; i++){
            y=id[i];
            for(int j=beg[i], k=0; j<beg[i+1]; j++){
                k=ch[k][s[j]-'a'];
                x=val[k];
                if(x&& mp.find({x, y})!=mp.end())
                    mp[{x,y}]=1;
                for(int l=last[k]; l; l=last[l]){
                    x=val[l];
                    if(mp.find({x, y})!=mp.end())
                        mp[{x,y}]=1;
                }
            }
        }
        for(int i=0; i<q; i++) 
            ans[i]=mp[{id[x[i]],id[y[i]]}];
    }
    int ans[2][N];
    map<pair<int,int>,int> mp[2];
    int main(){
        int T; scanf("%d", &T);
        for(int n, q; T--; puts("")){
            scanf("%d%d", &n, &q);
            input(n);
            calc_nt(n);
            build_trie(n);
            build_ac();
            preprocess(q, mp[1]);
            solve1(q, mp[0], ans[0]);
            solve2(n, q, mp[1], ans[1]);
            for(int i=0; i<q; i++) printf("%d%d", ans[0][i], ans[1][i]);
        }
    }
  • 相关阅读:
    《A First Course in Mathematical Modeling》-chaper1-差分方程建模
    《数学竞赛辅导》-一元函数积分学-7.24
    《University Calculus》-chape4-导数的应用-极值点的二阶导数检验法
    《A First Course in Probability》-chaper1-组合分析-方程整数解的个数
    《训练指南》——7.24
    《数学竞赛辅导》-一元函数微分学-7.23
    《University Calculus》-chape4-导数的应用-微分中值定理
    《训练指南》——7.21
    #424 Div2 E
    #424 Div2 C
  • 原文地址:https://www.cnblogs.com/Patt/p/5413800.html
Copyright © 2020-2023  润新知