「雅礼集训 2017 Day1」字符串

SOL:

     我们可以考虑SAM来跑这玩意。 我们发现 q*k=C是一个常数。

     那么我们可以分段处理:当k小于一个值的时候,我们可以在sam上暴力求出当前串的每一个子串的出现次数。

      复杂度O(kC+simga q)

     当k很大时,我们在SAM的fail树上倍增,我们暴力记下每一个前缀,对于每个前缀通过fail树向前走找到其后缀,即任意一子串。复杂度O(C+C/k*mlogn )

    这样写然而还是会T一个点,我们观察发现 simga q是限速步,我们考虑前缀和优化,强行套一颗主席树就好了:

    复杂度O(kClog k)

    然而本人比较懒,不想打主席树,面向数据把最后一个点水过去了。

    

#include<bits/stdc++.h>
#define SIZ 21
#define N 210007
#define M 567
#define LL long long
using namespace std;
struct Sp{
    int fa,ch[26],len,val;
};
int f[N][SIZ],q,len,l[N],r[N],k,now,n,m,c[N],id[N],L,R;
LL Ans;
char w[N>>1];
struct SAM{
    int tot=1,last=1,q,np,p;
    Sp T[N];
    void add(int x){
        q=++tot; T[q].len=T[last].len+1;
        for (;last&&!T[last].ch[x];last=T[last].fa) T[last].ch[x]=q;
        if (!last) T[q].fa=1; else {
            p=T[last].ch[x]; 
            if (T[p].len==T[last].len+1) T[q].fa=p;
            else {
                np=++tot; T[np]=T[p]; T[np].val=0;
                T[np].len=T[last].len+1;
                T[q].fa=T[p].fa=np;
                for(;last&&T[last].ch[x]==p;last=T[last].fa) T[last].ch[x]=np;
            }
        } 
        last=q; T[last].val=1;
    }
    void build() {
        for (int i=1;i<=tot;i++) f[i][0]=T[i].fa;
        for (int i=1;i<SIZ;i++) 
         for (int j=1;j<=tot;j++)
          f[j][i]=f[f[j][i-1]][i-1];
    }
    int que(int x,int val) {
        if (T[x].len<val) return 0;
        for (int i=SIZ-1;~i;i--) 
         if (T[f[x][i]].len>=val) x=f[x][i];
        return T[x].val;
    }
}Sam;
namespace work1 {
    int ans[M][M],gg[N][11][11];;
    int x;
    void solve() {
      if (k>10) {
        while (q--) {
            Ans=0;
            memset(ans,0,sizeof ans);
            scanf("%s%d%d",w+1,&L,&R); len=strlen(w+1);
            for (int i=1;i<=k;i++) {
                now=1;
                for (int j=i;j<=k;j++) {
                    x=w[j]-'a';
                    if (!Sam.T[now].ch[x]) break;
                    now=Sam.T[now].ch[x];
                    ans[i][j]=Sam.T[now].val;
                }
            }
            for (int i=L;i<=R;i++)
             Ans+=ans[l[i]][r[i]];
            printf("%lld\n",Ans);
        } }
       else {
           for (int i=0;i<m;i++) {
         if (i) memcpy(gg[i],gg[i-1],sizeof gg[i]);
          gg[i][l[i]][r[i]]++;
         }
        while (q--) {
            Ans=0;
//            read(w); read(L); read(R);
            scanf("%s%d%d",w+1,&L,&R);
            for (int i=1;i<=k;i++) {
                now=1;
                for (int j=i;j<=k;j++) {
                    x=w[j]-'a';
                    if (!Sam.T[now].ch[x]) break;
                    now=Sam.T[now].ch[x];
                    Ans+=1ll*gg[R][i][j]*Sam.T[now].val;
                    if (L) Ans-=1ll*gg[L-1][i][j]*Sam.T[now].val;
                }
            }
            printf("%lld\n",Ans);
        }
       }
    }    
}
namespace work2 {
    int x,Len;
    vector<int> v[N];
    void solve() {
     Sam.build();
     while (q--) {
          Ans=0; 
         scanf("%s%d%d",w+1,&L,&R);
         for (int i=L;i<=R;i++) 
           v[r[i]].push_back(r[i]-l[i]+1);
         now=1;Len=0;
         for (int i=1;i<=k;i++) {
             x=w[i]-'a';
             if (Sam.T[now].ch[x]) now=Sam.T[now].ch[x],Len++;else {
             while (now&&!Sam.T[now].ch[x]) now=Sam.T[now].fa;
             Len=Sam.T[now].len;
            if (!now) now=1,Len=0;else now=Sam.T[now].ch[x],Len++; }
//            cerr<<Len<<endl;
            for (auto j:v[i]) if (Len>=j) 
             Ans+=Sam.que(now,j);
            v[i].clear();
         } 
        printf("%lld\n",Ans); 
      } 
    }
}
signed main () {
    scanf("%d%d%d%d",&n,&m,&q,&k);
    scanf("%s",w+1);len=strlen(w+1);
    for (int i=1;i<=len;i++)  
     Sam.add(w[i]-'a');
    for (int i=1;i<=Sam.tot;i++) c[Sam.T[i].len]++;
    for (int i=1;i<=len;i++) c[i]+=c[i-1];
    for (int i=1;i<=Sam.tot;i++) id[c[Sam.T[i].len]--]=i;
    for (int i=Sam.tot;i;i--) Sam.T[Sam.T[id[i]].fa].val+=Sam.T[id[i]].val;
    for (int i=0;i<m;i++) scanf("%d%d",l+i,r+i),l[i]++,r[i]++;
    if (k<555) work1::solve();
    else 
    work2::solve();
    return 0;
}

 

posted @ 2018-04-12 21:26  泪寒之雪  阅读(414)  评论(0编辑  收藏  举报