[LOJ 6031]「雅禮集訓 2017 Day1」字符串

[LOJ 6031] 「雅禮集訓 2017 Day1」字符串

題意

給定一個長度爲 \(n\) 的字符串 \(s\), \(m\)\((l_i,r_i)\), 回答 \(q\) 個詢問. 每一個詢問會給定一個長度爲 \(k\) 的字符串 \(w\) 以及一對 \(L,R\), 求全部知足 \(i\in [L,R]\)\(w[l_i:r_i]\)\(s\) 中的出現次數之和.c++

\(n,m,k,q\le 1\times 10^5\), \(\sum |w|\le 1\times 10^5\).curl

題解

這sb題直接SAM暴力tm有90分...然而考場上把 \(k\)\(q\) 讀反了掛成10分...url

那個 \(\sum |w|\) 顯然就是 \(kq\), 因而 \(kq\le1\times 10^5\). 咱們一點都不天然地想到能夠根號分類.spa

\(k\le \sqrt m\) 的時候, 顯然 \(k^2q=O(m)k=O(m\sqrt m)\). 那麼咱們直接枚舉 \(w\) 的全部子串, 在 \(s\) 的SAM上倍增計算答案, 二分計算當前查詢區間中有多少個當前子串就能夠統計當前子串對答案的貢獻了. 時間複雜度是 \(O(k^2q\log n)=O(m\sqrt m\log n)\).code

\(k>\sqrt m\) 的時候, 顯然 \(kq=O(m)\Rightarrow q=O(\sqrt m)\). 因而咱們將全部 \((l_i,r_i)\) 分佈到 \(r_i\) 上, 而後邊在SAM上跑邊計算右端點爲當前位置的子串對答案的貢獻. 一次的複雜度是 \(O(k+m\log n)\). 總複雜度顯然是 \(O(m\sqrt m \log n)\).blog

而後就過了...字符串

參考代碼

#include <bits/stdc++.h>


namespace rvalue{
    const int MAXN=2e5+10;
    typedef long long intEx;

    int n;
    int q;
    int k;
    int m;
    int lg;
    int cnt=1;
    int last=1;
    int root=1;
    int s[MAXN];
    int prt[MAXN];
    int len[MAXN];
    int size[MAXN];
    char buf[MAXN];
    int pprt[20][MAXN];
    std::map<char,int> chd[MAXN];

    void Extend(char);

    namespace BF1{
        const int SQRN=350;

        std::vector<int> qpos[SQRN][SQRN];

        int main(){
#ifdef IRECT
            puts("BF1");
#endif
            for(int i=0;i<m;i++){
                int l,r;
                scanf("%d%d",&l,&r);
                qpos[l][r].push_back(i);
            }
            while(q--){
                int a,b;
                scanf("%s%d%d",buf,&a,&b);
                int cur=root,curlen=0;
                intEx ans=0;
                for(int i=0;i<k;i++){
                    while(cur!=root&&!chd[cur].count(buf[i])){
                        cur=prt[cur];
                        curlen=std::min(curlen,len[cur]);
                    }
                    if(chd[cur].count(buf[i])){
                        cur=chd[cur][buf[i]];
                        ++curlen;
                        int pos=cur;
                        for(int plen=curlen;plen>=1;plen--){
                            while(len[prt[pos]]>=plen)
                                pos=prt[pos];
                            auto& q=qpos[i-plen+1][i];
                            auto low=std::lower_bound(q.begin(),q.end(),a);
                            auto up=std::upper_bound(q.begin(),q.end(),b);
                            int cnt=up-low;
//                          printf("%d len=%d cnt=%d\n",i,plen,cnt);
                            ans+=1ll*cnt*size[pos];
                        }
                    }
                }
                printf("%lld\n",ans);
            }
            return 0;
        }
    }

    namespace BF2{
        std::vector<std::pair<int,int>> qlen[MAXN];

        int main(){
#ifdef IRECT
            puts("BF2");
#endif
            for(int i=0;i<m;i++){
                int l,r;
                scanf("%d%d",&l,&r);
                qlen[r].emplace_back(r-l+1,i);
            }
            while(q--){
                int a,b;
                scanf("%s%d%d",buf,&a,&b);
                int cur=root,curlen=0;
                intEx ans=0;
                for(int i=0;i<k;i++){
                    while(cur!=root&&!chd[cur].count(buf[i])){
                        cur=prt[cur];
                        curlen=std::min(curlen,len[cur]);
                    }
                    if(chd[cur].count(buf[i])){
                        cur=chd[cur][buf[i]];
                        ++curlen;
                        for(auto q:qlen[i]){
                            if(q.second<a||q.second>b)
                                continue;
                            if(curlen<q.first)
                                continue;
                            int pos=cur;
                            for(int j=lg;j>=0;j--)
                                if(len[pprt[j][pos]]>=q.first)
                                    pos=pprt[j][pos];
                            ans+=size[pos];
                        }
                    }
                }
                printf("%lld\n",ans);
            }
            return 0;
        }
    }

    int main(){
        scanf("%d%d%d%d",&n,&m,&q,&k);
        scanf("%s",buf);
        for(int i=0;i<n;i++)
            Extend(buf[i]);
        for(int i=1;i<=cnt;i++)
            s[i]=i;
        std::sort(s+1,s+cnt+1,[](int a,int b){return len[a]>len[b];});
        for(int i=1;i<=cnt;i++){
            size[prt[s[i]]]+=size[s[i]];
            pprt[0][i]=prt[i];
        }
        for(int j=1;(1<<j)<=cnt;j++){
            lg=j;
            for(int i=1;i<=cnt;i++)
                pprt[j][i]=pprt[j-1][pprt[j-1][i]];
        }
        if(1ll*k*k<=m)
            BF1::main();
        else
            BF2::main();
        return 0;
    }
    
    void Extend(char x){
        int p=last;
        int np=++cnt;
        size[last=np]=1;
        len[np]=len[p]+1;
        while(p&&!chd[p].count(x))
            chd[p][x]=np,p=prt[p];
        if(!p)
            prt[np]=root;
        else{
            int q=chd[p][x];
            if(len[q]==len[p]+1)
                prt[np]=q;
            else{
                int nq=++cnt;
                len[nq]=len[p]+1;
                chd[nq]=chd[q];
                prt[nq]=prt[q];
                prt[q]=nq;
                prt[np]=nq;
                while(p&&chd[p][x]==q)
                    chd[p][x]=nq,p=prt[p];
            }
        }
    }
}

int main(){
#if 0
    freopen("string.in","r",stdin);
    freopen("string.out","w",stdout);
#endif
    rvalue::main();
    return 0;
}

相關文章
相關標籤/搜索