zoukankan      html  css  js  c++  java
  • 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
    ",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
  • 相关阅读:
    【转】多线程:深入了解线程同步lock,Monitor,Mutex,同步事件和等待句柄(中)
    Mono初接触
    计算机颜色格式( 8位 16位 24位 32位色)
    我爱源代码
    Linux小白教程: tar的几种常用格式
    Linux小白教程:查看当前Linux的发行版本、内核(kernel)版本
    10大糟糕预测:
    一日编程小悟
    Linux小白教程:vi(shell文本编辑器)保存、退出命令
    C结构体中的函数指针与函数
  • 原文地址:https://www.cnblogs.com/oldjang/p/9447132.html
Copyright © 2011-2022 走看看