• 「雅礼集训 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
    ",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
    ",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
    ",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;
    }
  • 相关阅读:
    lua module
    lua require
    lua io
    lua table2
    lua table1
    【leetcode】魔术排列
    【leetcode】速算机器人
    【leetcode】黑白方格画
    【leetcode】根据数字二进制下 1 的数目排序
    【leetcode】插入区间
  • 原文地址:https://www.cnblogs.com/rrsb/p/8810532.html
Copyright © 2020-2023  润新知