后缀自动机

hdu 4622

题意:询问每个子串里包含的不同的子串的个数。

枚举每一个点作为起点做后缀自动机,维护自动机每个节点能有多少条路径到达。

#include <stdio.h>
#include <string.h>
#include <vector>
#include <iostream>
#include <set>
#include <map>
#include <queue>
#define ll long long
#define clr(a,b) memset(a,b,sizeof(a))
#define pii pair<int,int>
#define mpr(a,b) make_pair(a,b)
using namespace std;

const int ch = 26;
const int N=100000;
class SAM{
    public:
    int f[N],chd[N][ch+1],len[N],sw[200];
    //ch+1 number of tempt suffix at status
    int last,sz;
    void init(){
        clr(chd[0],0);
        f[0] = -1;
        chd[0][ch] = 1;
        last = 0;
        sz = 0;
        for(int i=0;i<26;i++)
            sw[i+'a'] = i;
    }
    int add(char inc,int l){
        int ans = 0;
        int c = sw[inc];
        int x = last;
        last = ++sz;
        clr(chd[sz],0);
        len[sz] = l;
        for(;x!=-1&&chd[x][c]==0;x=f[x]){
            chd[x][c] = sz;
            chd[last][ch] += chd[x][ch];
            ans += chd[x][ch];
        }
        if(x == -1){
            f[sz]=0;
        }
        else{
            int y = chd[x][c];
            if(len[y] == len[x]+1){
                f[sz]=y;
            }
            else{
                sz++;
                len[sz] = len[x] + 1;
                
                memcpy(chd[sz],chd[y],ch*4);
//                for(int i=0;i<ch;i++) chd[sz][i] = chd[y][i];
                chd[sz][ch] = 0;

                f[sz] = f[y];
                f[last] = f[y] = sz;

                for(;x!=-1&&chd[x][c]==y;x=f[x]){
                    chd[x][c] = sz;
                    chd[y][ch] -= chd[x][ch];
                    chd[sz][ch] += chd[x][ch];
                }
            }
        }
        return ans;
    }
}sam;

char s[100000];
int n,m;


int g[2005][2005];
int main(){
//    freopen("/home/zyc/Documents/Code/cpp/in","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%s",s);
        n = strlen(s);
        for(int i=0;i<n;i++){
            sam.init();
            for(int j=i;j<n;j++){
                if(j!=i)
                    g[i][j] = g[i][j-1] + sam.add(s[j],j-i+1);
                else
                    g[i][j] = sam.add(s[j],j-i+1);
            }
        }
        int Q;
        scanf("%d",&Q);
        while(Q--){
            int l,r;
            scanf("%d%d",&l,&r);
            l--;r--;
            printf("%d\n",g[l][r]);
        }
    }
    return 0;
}


hdu 4641

题意:给一个串在末尾动态增加字符,询问当前串中至少出现k次的子串个数。

与上题相比还需要维护增加字符时,以新加入字符为串尾的串的相应节点出现次数,只要更新parent树中当前last的祖先即可

#include <stdio.h>
#include <string.h>
#include <vector>
#include <iostream>
#include <set>
#include <map>
#include <queue>
#define ll long long
#define clr(a,b) memset(a,b,sizeof(a))
#define pii pair<int,int>
#define mpr(a,b) make_pair(a,b)
using namespace std;

const int ch = 26;
const int N=1000000;
int k;

class SAM{
    public:
    int f[N],chd[N][ch+2],len[N],sw[200];
    //ch+1 number of tempt suffix at status
    int last,sz;
    void init(){
        clr(chd[0],0);
        f[0] = -1;
        chd[0][ch] = 1;
        last = 0;
        sz = 0;
        for(int i=0;i<26;i++)
            sw[i+'a'] = i;
    }
    ll add(char inc,int l){
        int c = sw[inc];
        int x = last;
        last = ++sz;
        clr(chd[sz],0);
        len[sz] = l;
        for(;x!=-1&&chd[x][c]==0;x=f[x]){
            chd[x][c] = sz;
            chd[last][ch] += chd[x][ch];
        }
        if(x == -1){
            f[sz]=0;
        }
        else{
            int y = chd[x][c];
            if(len[y] == len[x]+1){
                f[sz]=y;
            }
            else{
                sz++;
                len[sz] = len[x] + 1;
                for(int i=0;i<ch;i++) chd[sz][i] = chd[y][i];
                chd[sz][ch] = 0;
                chd[sz][ch+1] = chd[y][ch+1];

                f[sz] = f[y];
                f[last] = f[y] = sz;

                for(;x!=-1&&chd[x][c]==y;x=f[x]){
                    chd[x][c] = sz;
                    chd[y][ch] -= chd[x][ch];
                    chd[sz][ch] += chd[x][ch];
                }

            }
        }
        ll ans = 0;
        x = last;
        for(x = last;x!=0;x=f[x]){
            if(chd[x][ch+1]>=k) break;
            chd[x][ch+1] ++;
            if(chd[x][ch+1]==k)
                ans += chd[x][ch];
        }
        return ans;
    }
}sam;

char s[100000];
int n,m;


int main(){
//    freopen("/home/zyc/Documents/Code/cpp/in","r",stdin);
    while(scanf("%d%d%d",&n,&m,&k)!=EOF){
        scanf("%s",s);
        sam.init();
        ll ans = 0;
        for(int i=0;i<n;i++)
            ans += sam.add(s[i],i+1);
        while(m--){
            int type;
            scanf("%d",&type);
            if(type==1){
                char c[2];
                scanf("%s",c);
                ans += sam.add(c[0],++n);
            }
            else{
                printf("%lld\n",ans);
            }
        }
    }
    return 0;
}


hdu 2609

题意:给你n个串,问有多少个是循环不同构。

可以使用最小表示法来求,后缀自动机的话先把串扩展成两倍,加进自动机,然后在自动机里求长度为原来长度的最小的串即可,需要遍历一遍。

最后用trie树判重。

#include <stdio.h>
#include <string.h>
#include <vector>
#include <iostream>
#include <set>
#include <map>
#include <queue>
#define ll long long
#define clr(a,b) memset(a,b,sizeof(a))
#define pii pair<int,int>
#define mpr(a,b) make_pair(a,b)
using namespace std;

char s[100000];
int n,m;

const int ch = 2;
const int N=1000000;

class SAM{
    public:
    int f[N],chd[N][ch],len[N],sw[200];
    int last,sz;
    void init(){
        clr(chd[0],0);
        last = 0;
        sz = 0;
        sw['0'] = 0;
        sw['1'] = 1;
    }
    void add(char inc,int l){
        int c = sw[inc];
        int x = last;
        last = ++sz;
        clr(chd[sz],0);
        len[sz] = l;
        for(;x&&chd[x][c]==0;x=f[x]) chd[x][c] = sz;
        int y = chd[x][c];
        if(y == 0){chd[x][c]=sz;f[sz]=0;}
        else if(len[y] == len[x]+1){f[sz]=y;}
        else{
            sz++;
            len[sz] = len[x] + 1;
            for(int i=0;i<ch;i++) chd[sz][i] = chd[y][i];
            f[sz] = f[y];
            f[last] = f[y] = sz;
            for(;x&&chd[x][c]==y;x=f[x]) chd[x][c] = sz;
            if(chd[x][c]==y) chd[x][c] = sz;

            for(;x;x=f[x]) sz = sz;
        }
    }
    void go(char s[],int dis){
        int rt = 0;
        for(int i=0;i<dis;i++){
            for(int j=0;j<ch;j++){
                if(chd[rt][j]){
                    s[i] = '0' + j;
                    rt = chd[rt][j];
                    break;
                }
            }
        }
    }
}sam;
class Trie{
    public:
    int trie[N][ch+1],sw[200];
    int top;
    void init(){
        top = 0;
        clr(trie[0],-1);
        sw['0'] = 0;
        sw['1'] = 1;
    }
    void insert(char s[],int len){
        int tmp = 0,nxt = 0;
        for(int i=0;i<len;i++,tmp=nxt){
            nxt = trie[tmp][sw[s[i]]];
            if(nxt==-1){
                top++;
                clr(trie[top],-1);
                trie[tmp][sw[s[i]]] = nxt =top;
            }
        }
        trie[tmp][ch] = 1;
    }
    int count(int rt){
        int sum = 0;
        for(int i=0;i<ch;i++){
            if(trie[rt][i]!=-1)
                sum += count(trie[rt][i]);
        }
        if(trie[rt][ch]!=-1) sum++;
        return sum ;
    }
}t;

int main(){
//    freopen("/home/zyc/Documents/Code/cpp/in","r",stdin);
    while(scanf("%d",&n)!=EOF){
        t.init();
        for(int i=0;i<n;i++){
            sam.init();
            scanf("%s",s);
            m = strlen(s);
            for(int i=0;i<m;i++) sam.add(s[i],i+1);
            for(int i=m;i<2*m;i++) sam.add(s[i-m],i+1);
            sam.go(s,m);
            t.insert(s,m);
        }
        printf("%d\n",t.count(0));
    }
    return 0;
}


spoj NSUBSTR

题意:求一个串中长度为i的串最多出现的次数。

记录自动机每个节点到达的次数,利用parent树来做。然后利用自动机的性质得到每个节点最长到达的串,即构造时的len,然后从大到小更新一遍。


#include <stdio.h>
#include <string.h>
#include <vector>
#include <iostream>
#include <set>
#include <map>
#include <queue>
#define ll long long
#define clr(a,b) memset(a,b,sizeof(a))
#define pii pair<int,int>
#define mpr(a,b) make_pair(a,b)
using namespace std;

const int ch = 26;
const int N=510000;
int k;

class SAM{
    public:
    int f[N],chd[N][ch+1],len[N],sw[200];
    vector<int> p[N];

    int last,sz;
    void init(){
        clr(chd[0],0);
        f[0] = -1;
        last = 0;
        sz = 0;
        for(int i=0;i<26;i++)
            sw[i+'a'] = i;
    }
    void add(char inc,int l){
        int c = sw[inc];
        int x = last;
        last = ++sz;
        clr(chd[sz],0);
        len[sz] = l;

        chd[last][ch]++;

        for(;x!=-1&&chd[x][c]==0;x=f[x]){
            chd[x][c] = sz;
        }
        if(x == -1){
            f[sz]=0;
        }
        else{
            int y = chd[x][c];
            if(len[y] == len[x]+1){
                f[sz]=y;
            }
            else{
                sz++;
                len[sz] = len[x] + 1;
                for(int i=0;i<ch;i++) chd[sz][i] = chd[y][i];
                chd[sz][ch] = 0;

                f[sz] = f[y];
                f[last] = f[y] = sz;

                for(;x!=-1&&chd[x][c]==y;x=f[x]){
                    chd[x][c] = sz;
                }
            }
        }
        return ;
    }
    void parent_tree(){
        for(int i=0;i<=sz;i++) p[i].clear();
        for(int v=1;v<=sz;v++){
            int u = f[v];
            p[u].push_back(v);
        }
        dfs_tree(0);
    }
    void dfs_tree(int u){
        for(int i=0;i<p[u].size();i++){
            int v = p[u][i];
            dfs_tree(v);
            chd[u][ch] += chd[v][ch];
        }
    }
}sam;

char s[1000000];
int a[1000000];
int n,m;


int main(){
//    freopen("/home/zyc/Documents/Code/cpp/in","r",stdin);
    scanf("%s",s);
    sam.init();
    n = strlen(s);
    for(int i=0;i<n;i++)
        sam.add(s[i],i+1);
    sam.parent_tree();
    for(int i=1;i<=sam.sz;i++){
        int l = sam.len[i];
        int w = sam.chd[i][ch];
        a[l] = max(a[l],w);
    }
    for(int i=n;i>=1;i--) a[i] = max(a[i+1],a[i]);
    for(int i=1;i<=n;i++)
        printf("%d\n",a[i]);

    return 0;
}

spoj SUBLEX

题意:询问一个串中第k小的不同的子串。

关键要得到自动机每个节点后面能够有多少种不同走法,有向无环图做下dp。然后走一遍自动机。

#include <stdio.h>
#include <string.h>
#include <vector>
#include <iostream>
#include <set>
#include <map>
#include <queue>
#define ll long long
#define clr(a,b) memset(a,b,sizeof(a))
#define pii pair<int,int>
#define mpr(a,b) make_pair(a,b)
using namespace std;

const int ch = 26;
const int N=200000;
char s[1000000];
int k;

class SAM{
    public:
    int f[N],chd[N][ch],len[N],sw[200];
    int q[N][ch],l[N];
    ll dp[N];
    bool vis[N];

    int last,sz;
    void init(){
        clr(vis,0);
        clr(dp,0);
        clr(chd[0],0);
        f[0] = -1;
        last = 0;
        sz = 0;
        for(int i=0;i<26;i++)
            sw[i+'a'] = i;
    }
    void add(char inc,int l){
        int c = sw[inc];
        int x = last;
        last = ++sz;
        clr(chd[sz],0);
        len[sz] = l;

        for(;x!=-1&&chd[x][c]==0;x=f[x]){
            chd[x][c] = sz;
        }
        if(x == -1) f[sz]=0;
        else{
            int y = chd[x][c];
            if(len[y] == len[x]+1) f[sz]=y;
            else{
                sz++;
                len[sz] = len[x] + 1;
                for(int i=0;i<ch;i++) chd[sz][i] = chd[y][i];

                f[sz] = f[y];
                f[last] = f[y] = sz;

                for(;x!=-1&&chd[x][c]==y;x=f[x]){
                    chd[x][c] = sz;
                }
            }
        }
        return ;
    }
    void dfs(int u){
        if(vis[u]) return ;
        vis[u] = 1;
        l[u] = 0;
        for(int i=0;i<ch;i++){
            int v = chd[u][i];
            if(v!=0){
                dfs(v);
                q[u][l[u]] = i;
                l[u] ++;
                dp[u] += dp[v];
            }
        }
        dp[u]++;
    }
    void go(ll k){
        int rt = 0,length = 0;
        while(k){
            if(rt!=0) k--;
            if(k<=0) break;
            for(int i=0;i<l[rt];i++){
                int nc = q[rt][i];
                int nxt = chd[rt][nc];
                if(dp[nxt]>=k){
                    rt = nxt ;
                    s[length++] = nc+'a';
                    break;
                }
                else
                    k -= dp[nxt];
            }
        }
        s[length] = 0;
        puts(s);
    }
}sam;

int n,m;


int main(){
//    freopen("/home/zyc/Documents/Code/cpp/in","r",stdin);
    scanf("%s",s);
    sam.init();
    n = strlen(s);
    for(int i=0;i<n;i++)
        sam.add(s[i],i+1);
    sam.dfs(0);
    int Q;
    scanf("%d",&Q);
    while(Q--){
        ll k;
        scanf("%lld",&k);
        sam.go(k);
    }

    return 0;
}



spoj LCS

spoj LCS2

这两题比较类似,求n个串的最长公共子串。

先以第一个串构造自动机,然后每个串都在自动机上走一遍,维护每个节点所能匹配的最长的串,对于所有串每个节点取个匹配的最小值,在对所有节点取个最大值即可。

#include <stdio.h>
#include <string.h>
#include <vector>
#include <iostream>
#include <set>
#include <map>
#include <queue>
#define ll long long
#define clr(a,b) memset(a,b,sizeof(a))
using namespace std;

const int N = 1000000,ch = 26;
char s[1000000];
const int inf = 1e8;

struct SAM{
    public:
    int chd[N][ch],f[N],sw[200],len[N];
    int val[N],tmp[N];
    vector<int> p[N];
    int sz,last;
    void init(){
        clr(chd[0],0);
        sz = 0;
        last = 0;
        f[0] = -1;
        for(int i=0;i<ch;i++)
            sw[i+'a'] = i;
    }
    void add(char tc,int l){
        int c = sw[(int)tc];
        int x = last;
        last = ++sz;
        len[last] = l;
        clr(chd[sz],0);

        for(;x!=-1&&chd[x][c]==0;x=f[x]) chd[x][c] = last;

        if(x==-1) f[last] = 0;
        else{
            int y = chd[x][c];
            if(len[y] == len[x] + 1) f[last] = y;
            else{
                sz ++;
                memcpy(chd[sz],chd[y],ch*4);
//                for(int i=0;i<ch;i++) chd[sz][i] = chd[y][i];
                len[sz] = len[x] + 1;

                f[sz] = f[y];
                f[y] = f[last] =sz;

                for(;x!=-1 && chd[x][c]==y;x=f[x]) chd[x][c] = sz;
            }
        }
    }
    void build(){
        for(int i=0;i<=sz;i++) p[i].clear();
        for(int i=0;i<=sz;i++)
            p[f[i]].push_back(i);
    }

    void go(char s[],int n){
        for(int i=0;i<=sz;i++) tmp[i] = 0;
        int rt = 0,l=0;
        for(int i=0;i<n;i++){
            int c = sw[(int)s[i]];
            if(chd[rt][c]){
                l++;
                rt = chd[rt][c];
            }else{
                while(rt!=-1&&chd[rt][c]==0) rt = f[rt];
                if(rt==-1){
                    rt = 0;
                    l = 0;
                }
                else{
                    l = len[rt] + 1;
                    rt = chd[rt][c];
                }
            }
            if(l>tmp[rt]) tmp[rt] = l;
        }
        dfs(0);
        for(int i=0;i<=sz;i++){
            if(tmp[i] > len[i]) tmp[i] = len[i];
            if(tmp[i]<val[i])
                val[i] = tmp[i];
        }
    }

    __inline void dfs(int u){
        int n = p[u].size();
        for(int i=0;i<n;i++){
            int v = p[u][i];
            dfs(v);
            if(tmp[v]>tmp[u]) tmp[u] = tmp[v];
        }
    }

    int get(){
        int ans = 0;
        for(int i=0;i<=sz;i++) ans = max(ans,val[i]);
        return ans;
    }
}sam;


int main(){
//    freopen("/home/zyc/Documents/Code/cpp/in","r",stdin);
    int cnt = 0 ;

    sam.init();
    scanf("%s",s);
    int n = strlen(s);
    for(int i=0;i<n;i++) sam.add(s[i],i+1);

    sam.build();

    for(int i=0;i<=sam.sz;i++) sam.val[i] = inf;
    while(scanf("%s",s)!=EOF){
        int n = strlen(s);
        sam.go(s,n);
        cnt ++;
    }
    if(cnt==0){
        printf("%d\n",n);
        return 0;
    }
    printf("%d\n",sam.get());
    return 0;
}


bzoj 2806

这题比较综合

就说一下后缀自动机的部分:要得到一个串在某个位置往前与其他模版串所能匹配的最长长度。把模版串用'$'号串起来,建立后缀自动机。然后一开始的串走一遍就可以了。

/**************************************************************
    Problem: 2806
    User: _LT_zyc
    Language: C++
    Result: Accepted
    Time:1232 ms
    Memory:79788 kb
****************************************************************/
 
#include <stdio.h>
#include <string.h>
#include <vector>
#include <iostream>
#include <set>
#include <map>
#include <queue>
#define ll long long
#define clr(a,b) memset(a,b,sizeof(a))
#define pii pair<int,int>
#define mpr(a,b) make_pair(a,b)
using namespace std;
 
const int ch = 3;
const int N=3000000;
class SAM{
    public:
    int f[N],chd[N][ch],len[N],sw[200];
    //ch+1 number of tempt suffix at status
    int last,sz;
    void init(){
        clr(chd[0],0);
        f[0] = -1;
        last = 0;
        sz = 0;
        sw['0'] = 0;
        sw['1'] = 1;
        sw['2'] = 2;
    }
    void add(char inc,int l){
        int c = sw[(int)inc];
        int x = last;
        last = ++sz;
        clr(chd[sz],0);
        len[sz] = l;
        for(;~x&&chd[x][c]==0;x=f[x]){
            chd[x][c] = sz;
        }
        if(x == -1) f[sz]=0;
        else{
            int y = chd[x][c];
            if(len[y] == len[x]+1)  f[sz]=y;
            else{
                sz++;
                len[sz] = len[x] + 1;
 
                memcpy(chd[sz],chd[y],sizeof(chd[sz]));
 
                f[sz] = f[y];
                f[last] = f[y] = sz;
 
                for(;~x&&chd[x][c]==y;x=f[x]){
                    chd[x][c] = sz;
                }
            }
        }
    }
    void go(char s[],int n,int a[]){
        int rt = 0,l=0;
        for(int i=0;i<n;i++){
            int c = sw[(int)s[i]];
            if(chd[rt][c]){
                l++;
                rt=chd[rt][c];
            }else{
                while(~rt&&chd[rt][c]==0) rt=f[rt];
 
                if(rt==-1){
                    rt=0;
                    l=0;
                }
                else {
                    l=len[rt]+1;
                    rt=chd[rt][c];
                }
            }
            a[i] = l;
        }
    }
}sam;
 
char s[1200000];
int n,m,a[1200000];
int dp[1200000],len;
int q[1200000],qid[1200000];
 
bool get(int gap){
    int l=0,r=0;
    for(int i=0;i<len;i++){
        if(i!=0) dp[i] = dp[i-1];
 
        int x = i-a[i];
        while(r>l&&qid[l]<x) l++;
 
        if(a[i]>=gap){
            dp[i] = max(dp[i],a[i]);
            if(r>l) dp[i] = max(dp[i],q[l]+i);
        }
 
        x = i-gap+1;
        if(x>=0){
            int w= dp[x]-x;
            while(r>l&&w>=q[r-1]) r--;
            qid[r] = x;
            q[r++] = w;
        }
        if(dp[i]*10 >= len*9) return 1;
    }
    return 0;
}
int main(){
//    freopen("/home/zyc/Documents/Code/cpp/in","r",stdin);
    sam.init();
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++){
        if(i!=0)
            sam.add('2',++len);
        scanf("%s",s);
        int l = strlen(s);
        for(int j=0;j<l;j++)
            sam.add(s[j],++len);
    }
    while(n--){
        scanf("%s",s);
        len = strlen(s);
        sam.go(s,len,a);
        int l=0,r=len;
        while(r!=l){
            int mid = (l+r)/2+1;
            if(get(mid)) l = mid;
            else r = mid-1;
        }
        printf("%d\n",r);
    }
    return 0;
}


hdu 4436

题意:给你多个由0~9组成的字符串,问其中所有子串代表的不同的数字的和。

位数高的在前面,所以先把串反过来,让位数高的后加进自动机。

多个串要判重所以先用'$'连接起来,建立自动机。

要得到每个节点后面的其他节点的值以及出现次数,然后当前节点的值就是 dp[u]  = dp[v] *10 + i*p[v];(i为转移的数字,p[v]为出现次数),还是dag上的dp

注意要把i=0的情况处理好。

答案就是dp[0]。

#pragma comment(linker, "/STACK:65536000")
#include <stdio.h>
#include <string.h>
#include <vector>
#include <iostream>
#include <set>
#include <map>
#include <queue>
#define ll long long
#define clr(a,b) memset(a,b,sizeof(a))
#define pii pair<int,int>
#define mpr(a,b) make_pair(a,b)
using namespace std;

const int N = 500000;
const int ch = 11;
const int mod = 2012;
class SAM{
    public :
    int chd[N][ch],len[N],sw[200],f[N];
    int sz,last,dp[N],vis[N],p[N];

    void init(){
        clr(chd,0);
        sz = 0;
        last = 0;
        len[0] = 0;
        f[0] = -1;
        sw['$'] = 10;
        for(int i=0;i<10;i++)
            sw[i+'0'] = i;
    }

    void add(char tc,int l){
        int c = sw[(int)tc];
        int x = last;
        last = ++sz;
        clr(chd[sz],0);
        len[sz] = l;

        for(;~x&&chd[x][c]==0;x=f[x]) chd[x][c] = sz;
        if(x==-1) f[sz] = 0;
        else{
            int y = chd[x][c];
            if(len[y] == len[x] + 1) f[sz] = y;
            else{
                sz++;
                memcpy(chd[sz],chd[y],sizeof(chd[sz]));
                len[sz] = len[x] + 1;

                f[sz] = f[y];
                f[y] = f[last] =sz;
                for(;~x&&chd[x][c]==y;x=f[x]) chd[x][c] = sz;
            }
        }
    }
    void dfs(int u){
        if(vis[u]) return ;
        vis[u] = 1;
        for(int i=0;i<ch-1;i++){
            int v = chd[u][i];
            if(v){
                dfs(v);
                if(i==0){
                    p[u]+=p[v];
                    if(p[u]>=mod) p[u]%=mod;
                    dp[u] += dp[v] * 10 +i*p[v];
                }else{
                    p[u]+=p[v]+1;
                    if(p[u]>=mod) p[u]%=mod;
                    dp[u] += dp[v] * 10 +i*(p[v]+1);
                }
                if(dp[u]>=mod) dp[u] %= mod;
            }
        }
    }
    int go(){
        for(int i=0;i<=sz;i++) p[i] = dp[i] =vis[i]= 0;
        dfs(0);
        return dp[0];
    }
}sam;

int n;
char s[200000];
int main(){
//    freopen("/home/zyc/Documents/Code/cpp/in","r",stdin);
    while(scanf("%d",&n)!=EOF){
        int ans = 0;
        int len = 0;
        sam.init();
        for(int i=0;i<n;i++){
            scanf("%s",s);
            int m = strlen(s);
            for(int j=0;j<m/2;j++) swap(s[j],s[m-j-1]);
            if(i!=0) sam.add('$',++len);
            for(int j=0;j<m;j++) sam.add(s[j],++len);
        }
        ans += sam.go();
        printf("%d\n",ans%mod);
    }
    return 0;
}


spoj COT4

看了一眼别人的做法,只能说我没打过ACM。有空在写。。。。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值