西安十五日游 day13 练习 【后缀自动机】

给一个字符串,求第k大子串,经典题

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
#include<iomanip> 
#include<vector>
#include<string>
#include<queue>
#include<stack>
#include<map>
#include<sstream>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])  
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define MAXN (180000+10)
#define Sigmasize (26) 
typedef unsigned long long ll;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return (a-b+llabs(a-b)/F*F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
class SAM {
public:
    char s[MAXN];
    int n;
    SAM():n(0){MEM(s) MEM(son) MEM(pre) MEM(step) last=tot=0;}
    SAM(char *_s){n=strlen(_s),memcpy(s,_s,sizeof(char)*(n+5)); MEM(son) MEM(pre) MEM(step) last=tot=0;}
    void mem(){n=0; MEM(s) MEM(son) MEM(pre) MEM(step) last=tot=0;}
    void mem(char *_s){n=strlen(_s);memcpy(s,_s,sizeof(char)*(n+5)); MEM(son) MEM(pre) MEM(step) last=tot=0; MEMI(l) MEMi(r) MEM(c) MEM(q)}

    int son[MAXN][Sigmasize+1],pre[MAXN],step[MAXN],last,tot;
    int l[MAXN],r[MAXN];
    void extend(char ch)
    {
        step[++tot]=step[last]+1;
        int p=last,np=tot;
        l[tot]=r[tot]=step[tot];

        for(;!son[p][ch];p=pre[p]) son[p][ch]=np;
        if (!p) pre[np]=1;
        else {
            int q=son[p][ch];
            if (step[q]==step[p]+1) pre[np]=q;
            else {
                step[++tot]=step[p]+1;
                int nq=tot;
                memcpy(son[nq],son[q],sizeof(son[q]));
                pre[nq]=pre[q];
                pre[q]=pre[np]=nq;
                for(;son[p][ch]==q;p=pre[p]) son[p][ch]=nq;
            }
        }
        last=np;
    }

    void build(){
        last=tot=1;
        Rep(i,n) extend(s[i]-'a');
    }
    int c[MAXN],q[MAXN],len[MAXN],sz[MAXN];
    void calc() {
        MEM(c)
        For(i,tot) c[step[i]]++;
        For(i,tot) c[i]+=c[i-1];
        For(i,tot) q[c[step[i]]--]=i;

        ForD(i,tot) {
            int u=q[i];
            l[pre[u]]=min(l[pre[u]],l[u]);
            r[pre[u]]=max(r[pre[u]],r[u]);
            sz[u]=1;
            Rep(c,26) if (son[u][c]) {
                sz[u]+=sz[son[u][c]];
            }
        }   
    }
    void dfs(int x,int k) {
        if (k==1) return; k--;
        Rep(c,26) if (son[x][c]) {
            if (sz[son[x][c]]>=k) {
                putchar(c+'a');
                dfs(son[x][c],k);
                return;
            } else k-=sz[son[x][c]];
        }
    }


}S1; 
char s[MAXN];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
    while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
    return x*f;
} 
int main()
{
//  freopen("D.in","r",stdin);
    scanf("%s",s);
    int n=strlen(s);
    S1.mem(s);
    S1.build();
    S1.calc();
    int q=read();
    while(q--) {
        S1.dfs(1,1+read());
        puts("");
    }
    return 0;
}

Glass Beads

求最小循环串

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
#include<iomanip> 
#include<vector>
#include<string>
#include<queue>
#include<stack>
#include<map>
#include<sstream>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])  
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define MAXN (40000+10)
#define Sigmasize (26) 
typedef unsigned long long ll;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return (a-b+llabs(a-b)/F*F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
class SAM {
public:
    char s[MAXN];
    int n;
    SAM():n(0){MEM(s) MEM(son) MEM(pre) MEM(step) last=tot=0;}
    SAM(char *_s){n=strlen(_s),memcpy(s,_s,sizeof(char)*(n+5)); MEM(son) MEM(pre) MEM(step) last=tot=0;}
    void mem(){n=0; MEM(s) MEM(son) MEM(pre) MEM(step) last=tot=0;}
    void mem(char *_s){n=strlen(_s);memcpy(s,_s,sizeof(char)*(n+5)); MEM(son) MEM(pre) MEM(step) last=tot=0; MEMI(l) MEMi(r) MEM(c) MEM(q)}

    int son[MAXN][Sigmasize+1],pre[MAXN],step[MAXN],last,tot;
    int l[MAXN],r[MAXN];
    void extend(char ch)
    {
        step[++tot]=step[last]+1;
        int p=last,np=tot;
        l[tot]=r[tot]=step[tot];

        for(;!son[p][ch];p=pre[p]) son[p][ch]=np;
        if (!p) pre[np]=1;
        else {
            int q=son[p][ch];
            if (step[q]==step[p]+1) pre[np]=q;
            else {
                step[++tot]=step[p]+1;
                int nq=tot;
                memcpy(son[nq],son[q],sizeof(son[q]));
                pre[nq]=pre[q];
                pre[q]=pre[np]=nq;
                for(;son[p][ch]==q;p=pre[p]) son[p][ch]=nq;
            }
        }
        last=np;
    }

    void build(){
        last=tot=1;
        Rep(i,n) extend(s[i]-'a');
    }
    int c[MAXN],q[MAXN],len[MAXN];
    void calc() {
        MEM(c)
        For(i,tot) c[step[i]]++;
        For(i,tot) c[i]+=c[i-1];
        For(i,tot) q[c[step[i]]--]=i;

        ForD(i,tot) {
            int u=q[i];
            l[pre[u]]=min(l[pre[u]],l[u]);
            r[pre[u]]=max(r[pre[u]],r[u]);
        }   
        MEM(len)
        For(i,tot) {
            len[i]=step[i]-step[pre[i]];
        }

    }
    int dfs(int x,int len) {
        For(i,len) {
            Rep(c,26) if (son[x][c]) {
                x=son[x][c]; break;
            }
        }
        return l[x];
    }


}S1; 
char s[MAXN];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
    while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
    return x*f;
} 
int main()
{
    freopen("H.in","r",stdin);
    int T=read();
    while(T--) {
        scanf("%s",s);
        int n=strlen(s);
        strncpy(s+n,s,n); s[2*n]=0;
        S1.mem(s);
        S1.build();
        S1.calc();
        printf("%d\n",S1.dfs(1,n)+1-n);
    }
    return 0;
}

Reincarnation

给出一个字符串,最长2000,q个询问,每次询问[l,r]区间内有多少个不同的字串。
转自:http://www.tuicool.com/articles/Mjuu2y
SAM 中的每个状态能够表示的不同子串的个数为 val - 父结点的 val。因此在构造自动机时,用变量 total 记录当前自动机能够表示的不同子串数,对每一次 extend 都更新 total 的值。将这个过程中的每一个 total 值都记录下了就能得到一个表示子串个数表。我们对字符串的每一个后缀都重新构造一遍 SAM 就可以得到一个二维的表。

对每次询问,在表中查找相应的值即可。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
#include<iomanip> 
#include<vector>
#include<string>
#include<queue>
#include<stack>
#include<map>
#include<sstream>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])  
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define MAXN (4000+10)
#define Sigmasize (26) 
typedef unsigned long long ll;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return (a-b+llabs(a-b)/F*F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
int f[MAXN][MAXN];
class SAM {
public:
    char s[MAXN];
    int n;
    SAM():n(0){MEM(s) MEM(son) MEM(pre) MEM(step) last=tot=0;}
    SAM(char *_s){n=strlen(_s),memcpy(s,_s,sizeof(char)*(n+5)); MEM(son) MEM(pre) MEM(step) last=tot=0;}
    void mem(){n=0; MEM(s) MEM(son) MEM(pre) MEM(step) last=tot=0;}
    void mem(char *_s){n=strlen(_s);memcpy(s,_s,sizeof(char)*(n+5)); MEM(son) MEM(pre) MEM(step) last=tot=0;}

    int son[MAXN][Sigmasize+1],pre[MAXN],step[MAXN],last,tot;
    void extend(char ch)
    {
        step[++tot]=step[last]+1;
        int p=last,np=tot;

        for(;!son[p][ch];p=pre[p]) son[p][ch]=np;
        if (!p) pre[np]=1;
        else {
            int q=son[p][ch];
            if (step[q]==step[p]+1) pre[np]=q;
            else {
                step[++tot]=step[p]+1;
                int nq=tot;
                memcpy(son[nq],son[q],sizeof(son[q]));
                pre[nq]=pre[q];
                pre[q]=pre[np]=nq;
                for(;son[p][ch]==q;p=pre[p]) son[p][ch]=nq;
            }
        }
        last=np;
    }

    void build(int he){
        last=tot=1;
        Rep(i,n) {
            extend(s[i]-'a');
            if (!i) f[he][he+i]=1;
            else f[he][he+i]=f[he][he+i-1]+step[last]-step[pre[last]];
        }
    }

}S1; 
char s[MAXN];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
    while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
    return x*f;
} 
int main()
{
//  freopen("J.in","r",stdin);
    int T=read();
    while(T--) {
        scanf("%s",s);
        int n=strlen(s);
        Rep(i,n) {
            S1.mem(s+i);
            S1.build(i);
        }
        int q=read();
        while(q--) {
            int l=read()-1,r=read()-1;
            printf("%d\n",f[l][r]);
        }
    }
    return 0;
}

str2int

给出n个数字,数字很长,用字符串读入,长度总和为10^5。求这n个字符串的所有子串(不重复)的和取模2012 。
转自:http://www.tuicool.com/articles/Mjuu2y
设父结点为 u 向数字 k 移动到的子结点为 v, 显然结点 v 的状态要在 sum 上增加 add=u->sum*10+u->cnt*k。即 u 的能表示的数字总和乘上10再加上到达 v 的方法总数乘上当前的个位数字 k。

#include<bits/stdc++.h> 
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])  
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define MAXN (100000*2+10000*2+10)
#define Sigmasize (10) 
typedef unsigned long long ll;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return (a-b+llabs(a-b)/F*F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
class SAM {
public:
    char s[MAXN];
    int n;
    SAM():n(0){MEM(s) MEM(son) MEM(pre) MEM(step) last=tot=0;}
    SAM(char *_s){n=strlen(_s),memcpy(s,_s,sizeof(char)*(n+5)); MEM(son) MEM(pre) MEM(step) last=tot=0;}
    void mem(){n=0; MEM(s) MEM(son) MEM(pre) MEM(step) last=tot=0;}
    void mem(char *_s){n=strlen(_s);memcpy(s,_s,sizeof(char)*(n+5)); MEM(son) MEM(pre) MEM(step) last=tot=0; MEMI(l) MEMi(r) }

    int son[MAXN][Sigmasize+1],pre[MAXN],step[MAXN],last,tot;
    int l[MAXN],r[MAXN];
    void extend(char ch)
    {
        step[++tot]=step[last]+1;
        int p=last,np=tot;
        l[tot]=r[tot]=step[tot];

        for(;!son[p][ch];p=pre[p]) son[p][ch]=np;
        if (!p) pre[np]=1;
        else {
            int q=son[p][ch];
            if (step[q]==step[p]+1) pre[np]=q;
            else {
                step[++tot]=step[p]+1;
                int nq=tot;
                memcpy(son[nq],son[q],sizeof(son[q]));
                pre[nq]=pre[q];
                pre[q]=pre[np]=nq;
                for(;son[p][ch]==q;p=pre[p]) son[p][ch]=nq;
            }
        }
        last=np;
    }

    void build(){
        last=tot=1;
        Rep(i,n) extend(s[i]-'0');
    }
    int c[MAXN],q[MAXN];
    int sum[MAXN],cnt[MAXN];
    void calc() {
        MEM(c)
        For(i,tot) c[step[i]]++;
        For(i,tot) c[i]+=c[i-1];
        For(i,tot) q[c[step[i]]--]=i;
        MEM(sum) MEM(cnt) cnt[1]=1;
        For(i,tot) {
            int u=q[i];
            Rep(c,10) if (son[u][c]){
                if (i==1&&c==0) continue;
                int v=son[u][c];
                cnt[v]+=cnt[u];
                sum[v]+=sum[u]*10+cnt[u]*c;
                sum[v]%=2012;
            }
        }   
        ll ans=0;
        For(i,tot) ans=(ans+sum[i])%2012;
        cout<<ans<<endl;
    }


}S1; 
int n;
char s[MAXN];
int main()
{
//  freopen("K.in","r",stdin);

    while(cin>>n) {
        int p=0;
        Rep(i,n) {
            scanf("%s",s+p);
            p+=strlen(s+p);
            s[p++]='9'+1;
        }
        s[p]=0;     
        S1.mem(s);
        S1.build();
        S1.calc();
    }

    return 0;
}

Common Substrings

A substring of a string T is defined as:

T( i, k)= TiTi +1… Ti+k -1, 1≤ i≤ i+k-1≤| T|.
Given two strings A, B and one integer K, we define S, a set of triples (i, j, k):

S = {( i, j, k) | k≥ K, A( i, k)= B( j, k)}.
You are to give the value of |S| for specific A, B and K.

直接匹配不行,还要向父节点走一遍,所以我们打个标记,上传

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
#include<iomanip> 
#include<vector>
#include<string>
#include<queue>
#include<stack>
#include<map>
#include<sstream> 
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])  
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define MAXN (111111*2+10)
#define Sigmasize (26*2) 
typedef unsigned long long ll;
int K;
class SAM {
public:
    char s[MAXN];
    int n;
    void mem(char *_s){
        n=strlen(_s);
        memcpy(s,_s,sizeof(char)*(n+5));
        Rep(i,2*n+2) {
            Rep(j,Sigmasize) son[i][j]=0;
            pre[i]=step[i]=cnt[i]=c[i]=mark[i]=0;
        }
        last=tot=0;
    }

    int son[MAXN][Sigmasize+1],pre[MAXN],step[MAXN],last,tot;

    void extend(char ch)
    {
        step[++tot]=step[last]+1;
        int p=last,np=tot;

        for(;!son[p][ch];p=pre[p]) son[p][ch]=np;
        if (!p) pre[np]=1;
        else {
            int q=son[p][ch];
            if (step[q]==step[p]+1) pre[np]=q;
            else {
                step[++tot]=step[p]+1;
                int nq=tot;
                memcpy(son[nq],son[q],sizeof(son[q]));
                pre[nq]=pre[q];
                pre[q]=pre[np]=nq;
                for(;son[p][ch]==q;p=pre[p]) son[p][ch]=nq;
            }
        }
        last=np;
        cnt[last]++;
    }
    int id(char c) {
        return c-((islower(c))?'a':'A'-26);
    }
    void build(){
        last=tot=1; 
        Rep(i,n) extend(id(s[i]));
    }
    int c[MAXN],q[MAXN],cnt[MAXN];
    void calc() {
        For(i,tot) c[step[i]]++;
        For(i,tot) c[i]+=c[i-1];
        For(i,tot) q[c[step[i]]--]=i;
        ForD(i,tot) {
            int u=q[i];
            cnt[pre[u]]+=cnt[u];
        }
    }
    ll mark[MAXN];
    void dp(char *s) {
        int t=0,p=0; 
        int n=strlen(s);
        ll ans=0;
        Rep(i,n) {
            int ch=id(s[i]);
            if (son[t][ch]) p++,t=son[t][ch]; 
            else {
                while (t && !son[t][ch]) {
                    t=pre[t]; p=step[t];
                }
                if (!t) t=1,p=0;
                else {
                    p=step[t]+1; t=son[t][ch];
                }
            }
            if (p>=K) {
                ans+=(ll)max(0,min(step[t],p)-max(K-1,step[pre[t]] ) )  * cnt[t];
            }
            if (step[pre[t]]>=K) mark[pre[t]]++;
        }
        ForD(i,tot){
            int u=q[i];
            if (mark[u]) ans+=(ll)mark[u]*cnt[u] * max(0,(step[u]-max(K-1,step[pre[u]])));
            if (step[pre[u]]>=K) mark[pre[u]]+=mark[u];
        }
        printf("%lld\n",ans);
    }


}S1; 
char s[MAXN];
int main()
{
//  freopen("L.in","r",stdin);

    while(scanf("%d",&K)&&K) {
        scanf("%s",s);
        S1.mem(s);
        S1.build();
        scanf("%s",s);
        S1.calc();
        S1.dp(s);
    }

    return 0;
}

AB String

求第k大没出现的字符串,

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
#include<iomanip> 
#include<vector>
#include<string>
#include<queue>
#include<stack>
#include<map>
#include<sstream>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])  
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define MAXN (40000+10)
#define Sigmasize (2) 
typedef unsigned long long ll;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return (a-b+llabs(a-b)/F*F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
class SAM {
public:
    char s[MAXN];
    int n;
    SAM():n(0){MEM(s) MEM(son) MEM(pre) MEM(step) last=tot=0;}
    SAM(char *_s){n=strlen(_s),memcpy(s,_s,sizeof(char)*(n+5)); MEM(son) MEM(pre) MEM(step) last=tot=0;}
    void mem(){n=0; MEM(s) MEM(son) MEM(pre) MEM(step) last=tot=0;}
    void mem(char *_s){n=strlen(_s);memcpy(s,_s,sizeof(char)*(n+5)); MEM(son) MEM(pre) MEM(step) last=tot=0; MEMI(l) MEMi(r) MEM(c) MEM(q)}

    int son[MAXN][Sigmasize+1],pre[MAXN],step[MAXN],last,tot;
    int l[MAXN],r[MAXN];
    void extend(char ch)
    {
        step[++tot]=step[last]+1;
        int p=last,np=tot;
        l[tot]=r[tot]=step[tot];

        for(;!son[p][ch];p=pre[p]) son[p][ch]=np;
        if (!p) pre[np]=1;
        else {
            int q=son[p][ch];
            if (step[q]==step[p]+1) pre[np]=q;
            else {
                step[++tot]=step[p]+1;
                int nq=tot;
                memcpy(son[nq],son[q],sizeof(son[q]));
                pre[nq]=pre[q];
                pre[q]=pre[np]=nq;
                for(;son[p][ch]==q;p=pre[p]) son[p][ch]=nq;
            }
        }
        last=np;
    }

    void build(){
        last=tot=1;
        Rep(i,n) extend(s[i]-'A');
    }
    int c[MAXN],q[MAXN],len[MAXN],sz[MAXN];
    void calc() {
        MEM(c)
        For(i,tot) c[step[i]]++;
        For(i,tot) c[i]+=c[i-1];
        For(i,tot) q[c[step[i]]--]=i;

        ForD(i,tot) {
            int u=q[i];
            l[pre[u]]=min(l[pre[u]],l[u]);
            r[pre[u]]=max(r[pre[u]],r[u]);
            sz[u]=1;
            Rep(c,Sigmasize) if (son[u][c]) {
                sz[u]+=sz[son[u][c]];
            }
        }   
    }
    int dfs(int x,int len) {
        if(!len) return 0;
        int ans=0;
        Rep(c,Sigmasize) if (son[x][c]) {
                ans+=dfs(son[x][c],len-1);
        } else ans+=1<<len-1;
        return ans;
    }
    char st[MAXN];
    int dfs(int x,int k,int len,int l) {
        if(!len) return 0;
        int ans=0;
        Rep(c,Sigmasize) {
            st[l]=c+'A';
            if (son[x][c]) {
                    int p=dfs(son[x][c],k,len-1,l+1);
                    ans+=p;
                    if (p>=k) {
                        return ans;
                    }
                    k-=p;
            } else {
                int p=1<<len-1;
                ans+=p;
                if (p>=k) {
                    Rep(i,l) putchar(st[i]);
                    putchar(st[l]);
                    len--;
                    while(len) {
                        if ((1<<len-1)>=k) putchar('A');
                        else {
                            k-=1<<len-1;
                            putchar('B');
                        }
                        --len;
                    }
                    return ans;
                }
                k-=p; 
            }
        }
        return ans;
    }


}S1; 
char s[MAXN];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
    while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
    return x*f;
} 
int main()
{
//  freopen("O.in","r",stdin);
    int T=read();
    while(T--) {
        scanf("%s",s);
        int n=strlen(s);
        S1.mem(s);
        S1.build();
        S1.calc();
        int q=read();
        while(q--) {
            int k=read();
            for(int len=1;;len++) {
                int sz=S1.dfs(1,len);
                if (k>sz) k-=sz;
                else {
                    S1.dfs(1,k,len,0);
                    puts("");
                    break;
                } 
            }
        }
    }
    return 0;
}

New Distinct Substrings

字符串本质不同子串数

#include<bits/stdc++.h> 
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])  
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define MAXN (90000*2+10)
#define Sigmasize (26) 
typedef unsigned long long ll;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return (a-b+llabs(a-b)/F*F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
class SAM {
public:
    char s[MAXN];
    int n;
    SAM():n(0){MEM(s) MEM(son) MEM(pre) MEM(step) last=tot=0;}
    SAM(char *_s){n=strlen(_s),memcpy(s,_s,sizeof(char)*(n+5)); MEM(son) MEM(pre) MEM(step) last=tot=0;}
    void mem(){n=0; MEM(s) MEM(son) MEM(pre) MEM(step) last=tot=0;}
    void mem(char *_s){n=strlen(_s);memcpy(s,_s,sizeof(char)*(n+5)); MEM(son) MEM(pre) MEM(step) last=tot=0;  }

    int son[MAXN][Sigmasize+1],pre[MAXN],step[MAXN],last,tot;

    void extend(char ch)
    {
        step[++tot]=step[last]+1;
        int p=last,np=tot;

        for(;!son[p][ch];p=pre[p]) son[p][ch]=np;
        if (!p) pre[np]=1;
        else {
            int q=son[p][ch];
            if (step[q]==step[p]+1) pre[np]=q;
            else {
                step[++tot]=step[p]+1;
                int nq=tot;
                memcpy(son[nq],son[q],sizeof(son[q]));
                pre[nq]=pre[q];
                pre[q]=pre[np]=nq;
                for(;son[p][ch]==q;p=pre[p]) son[p][ch]=nq;
            }
        }
        last=np;
    }

    void build(){
        last=tot=1;
        Rep(i,n) extend(s[i]-'a');
    }
    ll calc() {
        ll ans=0;
        For(i,tot) {
            ans+=max(0,step[i]-step[pre[i]]);
        }   
        cout<<ans<<endl;
    }


}S1; 
char s[MAXN];
int main()
{
//  freopen("U.in","r",stdin);

    int T;cin>>T;
    while(T--) {
        scanf("%s",s);
        S1.mem(s);
        S1.build();
        ll tot=0;
        S1.calc();
    }

    return 0;
}

Boring counting

一个字符串有多少子串,出现了至少两次且不重叠
eg:ababa aba[1.3]和aba[3.5]重叠,所以不算,ab[1.2]和ab[3.4]算
后缀自动机上每个节点的所以后缀right集合相同(right集合就是后缀出现的位置,比如ababa中aba的right视为(3,5)),所以只要计算出可能后缀的长度,出现的最左最右的位置,就行了

#include<bits/stdc++.h> 
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p])  
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define MAXN (90000+10)
#define Sigmasize (26) 
typedef unsigned long long ll;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return (a-b+llabs(a-b)/F*F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
class SAM {
public:
    char s[MAXN];
    int n;
    SAM():n(0){MEM(s) MEM(son) MEM(pre) MEM(step) last=tot=0;}
    SAM(char *_s){n=strlen(_s),memcpy(s,_s,sizeof(char)*(n+5)); MEM(son) MEM(pre) MEM(step) last=tot=0;}
    void mem(){n=0; MEM(s) MEM(son) MEM(pre) MEM(step) last=tot=0;}
    void mem(char *_s){n=strlen(_s);memcpy(s,_s,sizeof(char)*(n+5)); MEM(son) MEM(pre) MEM(step) last=tot=0; MEMI(l) MEMi(r) }

    int son[MAXN][Sigmasize+1],pre[MAXN],step[MAXN],last,tot;
    int l[MAXN],r[MAXN];
    void extend(char ch)
    {
        step[++tot]=step[last]+1;
        int p=last,np=tot;
        l[tot]=r[tot]=step[tot];

        for(;!son[p][ch];p=pre[p]) son[p][ch]=np;
        if (!p) pre[np]=1;
        else {
            int q=son[p][ch];
            if (step[q]==step[p]+1) pre[np]=q;
            else {
                step[++tot]=step[p]+1;
                int nq=tot;
                memcpy(son[nq],son[q],sizeof(son[q]));
                pre[nq]=pre[q];
                pre[q]=pre[np]=nq;
                for(;son[p][ch]==q;p=pre[p]) son[p][ch]=nq;
            }
        }
        last=np;
    }

    void build(){
        last=tot=1;
        Rep(i,n) extend(s[i]-'a');
    }
    int c[MAXN],q[MAXN];
    void calc() {
        MEM(c)
        For(i,tot) c[step[i]]++;
        For(i,tot) c[i]+=c[i-1];
        For(i,tot) q[c[step[i]]--]=i;

        ForD(i,tot) {
            int u=q[i];
            l[pre[u]]=min(l[pre[u]],l[u]);
            r[pre[u]]=max(r[pre[u]],r[u]);
        }   
        ll ans=0;
        For(i,tot) ans+=max(0,min(r[i]-l[i],step[i])-step[pre[i]] );
        cout<<ans<<endl;
    }


}S1; 
char s[MAXN];
int main()
{
//  freopen("V.in","r",stdin);

    while(1) {
        scanf("%s",s);
        if (strcmp(s,"#")==0) return 0;
        S1.mem(s);
        S1.build();
        S1.calc();
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值