1. 程式人生 > >【bzoj4212】神牛的養成計劃

【bzoj4212】神牛的養成計劃

Portal --> bzoj4212

Description

​  給你\(n\)個字串,接下來有\(m\)個詢問,每個詢問由兩個給定的字串\(s_1\)\(s_2\)組成,對於每個詢問輸出\(n\)個字串中有多少個同時滿足\(s_1\)是其字首且\(s_2\)是其後綴,強制線上

​​  資料範圍:\(n<=2000,m<=100000\)\(n\)個字串總長度以及詢問字串總長度均\(<=2000000\)

​  

Solution

​​  (怎麼感覺自己好像沒有學過trie一樣是因為太久沒有寫所以根本沒有往那個方向想嗎==)

​  最暴力的做法的話。。想法很簡單:先確定哪些字串滿足\(s_1\)

是字首,再看其中滿足\(s_2\)是字尾的數量

​  字首這種東西的話,如果說我們將\(n\)個字串丟到trie裡面,將dfs一遍之後各個字串結尾對應節點的訪問順序存在一個數組裡面,那麼對於一個詢問\((s_1,s_2)\),滿足\(s_1\)是字首的字串的結尾對應節點必定在一個子樹當中,反應到數組裡面的話就是一個區間

​​  那所以接下來我們要做的就是查這個區間內的字串有多少個滿足\(s_2\)是字尾,只要將所有的串反轉然後丟到trie裡面,就又轉成查字首的問題了,解決方式和上面一樣

​​  至於區間這個問題,直接可持久化一下就好了

​  

​  mark:沒事還是不要隨便用getline好了==評測的時候超級容易翻車

​​  mark:字首什麼的也是應該考慮一下trie啊qwq不要看到字串什麼的就滿腦子sa、sam之類的

​  

​  程式碼大概長這個樣子

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define mp make_pair
#define Pr pair<int,int>
using namespace std;
const int N=2010,L=2000010,C=26;
string s[N],s1,s2;
char tmps[L];
int st[N],lis[N];
int n,tot,lastans,m;
namespace T1{/*{{{*/
    const int N=::L;
    int ch[N][C],st[N],ed[N];
    vector<int> mark[N];
    int tot,rt;
    void init(){rt=1;tot=1;}
    void insert(string s,int id){
        int len=s.length(),now=rt,c;
        for (int i=0;i<len;++i){
            c=s[i]-'a';
            if (!ch[now][c]) ch[now][c]=++tot;
            now=ch[now][c];
        }
        mark[now].push_back(id);
    }
    void dfs(int x){
        bool have=mark[x].size();
        if (mark[x].size()){
            st[x]=lis[0]+1; 
            for (int i=0;i<mark[x].size();++i)
                lis[++lis[0]]=mark[x][i];
        }
        bool flag=false;
        for (int i=0;i<C;++i){
            if (!ch[x][i]) continue;
            dfs(ch[x][i]);
            if (!flag&&!have)
                st[x]=st[ch[x][i]];
            flag=true;
        }
        ed[x]=lis[0];
    }
    void get_order(){lis[0]=0; dfs(rt);}
    Pr query(string s){
        int now=rt,len=s.length(),c;
        for (int i=0;i<len;++i){
            //printf("%c\n",s[i]);
            c=(s[i]-'a'+lastans)%C;
            now=ch[now][c];
        }
        if (!now) return mp(-1,-1);
        return mp(st[now],ed[now]);
    }
}/*}}}*/
namespace T2{/*{{{*/
    const int N=::L;
    int ch[N][C],rt[::N],cnt[N];
    int tot;
    void init(){tot=0;rt[0]=0;}
    int newnode(int pre){
        cnt[++tot]=cnt[pre];
        for (int i=0;i<C;++i) ch[tot][i]=ch[pre][i];
        return tot;
    }
    void _insert(int pre,int &x,string &s,int loc){
        x=newnode(pre);
        ++cnt[x];
        if (loc<0) return;
        int c=(s[loc]-'a'+lastans)%C;
        _insert(ch[pre][c],ch[x][c],s,loc-1);
    }
    void insert(int pre,int x,string &s){_insert(rt[pre],rt[x],s,s.length()-1);}
    int query(int l,int r,string s){
        int nowl=rt[l],nowr=rt[r],c,len=s.length();
        int ret=0;
        for (int i=len-1;i>=0&&(nowl||nowr);--i){
            c=(s[i]-'a'+lastans)%C;
            nowl=ch[nowl][c];
            nowr=ch[nowr][c];
        }
        return cnt[nowr]-cnt[nowl];
    }
}/*}}}*/
void print(string s){
    int len=s.length();
    for (int i=0;i<len;++i) printf("%c",s[i]);
    printf("\n");
}
void get_s(string &s){
    scanf("%s",tmps);
    int len=strlen(tmps);
    s.resize(0);
    for (int i=0;i<len;++i)
        s.push_back(tmps[i]);
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("a.in","r",stdin);
#endif
    char ch;
    Pr rec;
    scanf("%d\n",&n);
    T1::init(); T2::init();
    lastans=0;
    for (int i=1;i<=n;++i){
        get_s(s[i]);
        //print(s[i]);
        T1::insert(s[i],i);
    }
    T1::get_order();
    for (int i=1;i<=lis[0];++i){
        T2::insert(i-1,i,s[lis[i]]);
    }
    scanf("%d\n",&m);
    for (int i=1;i<=m;++i){
        get_s(s1);
        get_s(s2);
        //print(s1);print(s2);
        rec=T1::query(s1);
        if (rec.first!=-1) 
            lastans=T2::query(rec.first-1,rec.second,s2);
        else lastans=0;
        printf("%d\n",lastans);
    }
}