codeforces 235C

题目大意

  给若干个询问串,询问他以及他的循环同构串在原串中出现了多少次

题解

  显然如果不包含循环同构的条件只要在sam上跑一遍,然后找到minlen>=串长的parent树上最高的节点就行了,答案就是这个节点的right集合的大小。对于循环同构的话,只要把串复制一份接在后面,然后统计n次即可。注意走到了同一个节点只能算一次。

 1 #include <bits/stdc++.h>
 2 #define ll long long
 3 #define inf 0x6fffffff
 4 #define N 1000086
 5 using namespace std;
 6 int read(){
 7     int x=0,f=1;char ch=getchar();
 8     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 9     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
10     return x*f;
11 }
12 char s[N];
13 struct SAM
14 {
15     int dis[2*N],son[2*N][30],fa[2*N],sum[2*N];
16     int tmp[2*N],rk[2*N];
17     int vis[2*N];
18     int last,cnt,root,n;
19     void init(){last=cnt=root=1;n=strlen(s+1);}
20     int newnode(int v){dis[++cnt]=v;return cnt;}
21     void ins(int ch)
22     {
23         int p=last,np=newnode(dis[p]+1);
24         last=np;sum[np]=1;
25         for(;p&&!son[p][ch];p=fa[p])son[p][ch]=np;
26         if(!p)fa[np]=root;
27         else{
28             int q=son[p][ch];
29             if(dis[q]==dis[p]+1)fa[np]=q;
30             else{
31                 int nq=newnode(dis[p]+1);
32                 memcpy(son[nq],son[q],sizeof(son[q]));
33                 fa[nq]=fa[q];
34                 fa[q]=fa[np]=nq;
35                 for(;son[p][ch]==q;p=fa[p])son[p][ch]=nq;
36             }
37         }
38     }
39     void build()
40     {
41         init();
42         for(int i=1;i<=n;i++)ins(s[i]-'a');
43         for(int i=1;i<=cnt;i++)tmp[dis[i]]++;
44         for(int i=1;i<=cnt;i++)tmp[i]+=tmp[i-1];
45         for(int i=cnt;i;i--)rk[tmp[dis[i]]--]=i;
46         for(int i=cnt;i;i--)sum[fa[rk[i]]]+=sum[rk[i]];
47     }
48     void work(int id)
49     {
50         int n=strlen(s+1);
51         int p=root,ans=0,nl=0;
52         for(int i=1;i<2*n;i++)
53         {
54             int ch=(i<=n)?s[i]-'a':s[i-n]-'a';
55             while(p&&son[p][ch]==0){p=fa[p];nl=dis[p];}
56             if(p==0){p=root;nl=0;}
57             else{p=son[p][ch];nl++;}
58             while(fa[p]&&dis[fa[p]]>=n){p=fa[p];nl=dis[p];}
59             if(nl>=n&&(vis[p]!=id))
60             {
61                 vis[p]=id;ans+=sum[p];
62             }
63         }
64         printf("%d\n",ans);
65     }
66 }T;
67 int main()
68 {
69     scanf("%s",s+1);
70     T.build();
71     int n=read();
72     for(int i=1;i<=n;i++)
73     {
74         scanf("%s",s+1);T.work(i);
75     }
76     return 0;
77 }
View Code

 

posted @ 2018-08-09 09:56  OldJang  阅读(248)  评论(0编辑  收藏  举报