dtoj3198 字符串(string)

令 $ s $ 与 $ w $ 为两字符串,定义:

1. $ w[l, r] $ 表示字符串 $ w $ 在区间 $ [l, r] $ 中的子串;
2. $ w $ 在 $ s $ 中出现的频率定义为$ w $ 在 $ s $ 中出现的次数;
3. $ f(s, w, l, r) $ 表示 $ w[l, r] $ 在 $ s $ 中出现的频率。

比如 $ f(\texttt{ababa}, \texttt{aba}, 1, 3) = 2 $。

现在给定串 $ s $,$ m $ 个区间 $ [l, r] $ 和长度 $ k $,你要回答 $ q $ 个询问,每个询问给你一个长度为 $ k $ 的字符串 $ w $ 和两个整数 $ a, b $,求:

$$ \sum\limits_{i = a} ^ b f(s, w, l_i, r_i) $$


Sol

对S串建出sam,预处理每个节点right集合大小。

注意到Q*k=1e5 考虑分类讨论:、

1.Q>k

枚举Q,枚举w的每一个子串[l,r],二分出询问[l,r]中有多少个在[a,b]中,乘上right大小即可。

效率O(q*k^2*log)=O(wsqrt(w)log)

2.Q<k

枚举Q,枚举w的每一位,记录在sam上匹配到了哪个点,匹配长度是多少。

然后枚举a到b的每一个区间[l,r],先走到r,然后倍增到l,加上right即可

效率O(Q(k+m))

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#define maxn 400005 
using namespace std;
int n,li,len,ls,cnt,ans[maxn],tr[maxn][94],fail[maxn],head[maxn],tot;
int dfn[maxn],ed[maxn],sc,c[maxn];
char ch[maxn],s[maxn];
struct no{
    int v,nex;
}e[maxn];
void add(int t1,int t2){
    e[++tot].v=t2;e[tot].nex=head[t1];head[t1]=tot;
}
struct bit{
    int tr[maxn];
    void add(int i,int v){
        for(;i<=cnt;i+=i&-i)tr[i]+=v;
    }
    int ask(int i){
        int sum=0;for(;i;i-=i&-i)sum+=tr[i];return sum;
    }
}T;
struct node{int p,id;};
vector<node>q[maxn];
vector<int>G[maxn];
void ins(int l,int id){
    for(int i=1;i<=l;i++)ch[i]-=33;
    int k=0;
    for(int i=1;i<=l;i++){
        if(!tr[k][ch[i]])tr[k][ch[i]]=++cnt;
        k=tr[k][ch[i]];
    }
    k=0;
    for(int i=l;i>0;i--){
        if(!tr[k][ch[i]])tr[k][ch[i]]=++cnt;
        k=tr[k][ch[i]];ed[i]=k;
    }
    k=0;
    q[0].push_back((node){ed[li+1],id});
    cout<<ed[2]<<' '<<ed[li+1]<<' '<<id<<endl; 
    for(int i=1;i+li<=l;i++){
        k=tr[k][ch[i]];
        if(i+li==l)q[k].push_back((node){-1,id});
        else q[k].push_back(node{ed[i+li+1],id});
        
    }
}
void build(){
    queue<int>q;
    for(int i=0;i<94;i++)if(tr[0][i])q.push(tr[0][i]);
    while(!q.empty()){
        int k=q.front();q.pop();
        add(fail[k],k);
        for(int i=0;i<94;i++){
            if(tr[k][i])fail[tr[k][i]]=tr[fail[k]][i],q.push(tr[k][i]);
            else tr[k][i]=tr[fail[k]][i];
        }
    }
}
void dfs(int k){
    dfn[k]=++sc;
    for(int i=head[k];i;i=e[i].nex)dfs(e[i].v);
    ed[k]=sc;
}
void solve(int k){
    for(int i=head[k];i;i=e[i].nex)solve(e[i].v);
    for(int i=0;i<G[k].size();i++){
        T.add(G[k][i],1);
    }
    for(int i=0;i<q[k].size();i++){
        node t=q[k][i];
        if(t.id==1)cout<<k<<' '<<t.p<<' '<<G[k].size()<<endl;
        if(t.p==-1)ans[t.id]+=T.ask(ed[0]);
        else ans[t.id]+=T.ask(ed[t.p])-T.ask(dfn[t.p]-1);
    }
    for(int i=0;i<G[k].size();i++)T.add(G[k][i],-1);
}
int main(){ 
    cin>>li;scanf(" %s",s+1);n=strlen(s+1);
    for(int i=1;i<=n;i++)s[i]-=33;
    cin>>n;
    for(int i=1;i<=n;i++){
        scanf("%s",ch+1);
        int l=strlen(ch+1);
        if(l<=li)ans[i]=n-l+1;
        else ins(l,i);
    }
    build();dfs(0);
    cout<<"haha "<<tr[0]['z'-33]<<endl;
    int k=0;c[n+1]=dfn[0];
    for(int i=n;i>=1;i--){
        k=tr[k][s[i]];c[i]=k;
    }
    
    k=0;G[0].push_back(li);
    for(int i=1;i+li<=n;i++){
        k=tr[k][s[i]];
        cout<<k<<' '<<fail[k]<<' '<<c[i+li+1]<<endl;
        G[k].push_back(c[i+li+1]); 
    }
    solve(0); 
    for(int i=1;i<=n;i++)printf("%d\n",ans[i]);
    return 0;
}
View Code

 

posted @ 2020-01-31 16:42  liankewei123456  阅读(246)  评论(0编辑  收藏  举报