zoukankan      html  css  js  c++  java
  • 求回文串个数

    先整理各路大神的题解 Orz,以后再埋坑

    SP7586 NUMOFPAL - Number of Palindromes

    Description

    求一个串中包含几个回文串。

    Input

    输入一个字符串S

    Output

    包含的回文串的个数.

    思路一:

    用马拉车求出预处理后以每个字母处的回文半径P[i],遍历一遍,ans=ans+P[i]/2,最终ans就是答案

    答案是以每一位为中心的回文串长度/2的和,(如果添加字符则为回文半径长度/2。)

    不能理解的话,可以看下这个

    # a # a # b # a # a #

    1   2  3  2 1  6 1  2  3  2  1

    数字对应于每一个位置的回文半径

    .(实际上减去1才是,但是计算的时候要加上1,所以代码里面直接用了这个.)

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<iostream>
     4 #include<cstring>
     5 #define R register
     6 
     7 using namespace std;
     8 
     9 const int maxn=1008;
    10 
    11 char ch[maxn];
    12 char s[maxn<<2];
    13 int len,RL[maxn<<2],MaxRight,center,ans;
    14 int main()
    15 {
    16     scanf("%s",ch);
    17     len=strlen(ch);
    18     for(R int i=0;i<len;i++)s[2*i+1]=ch[i];
    19     len=2*len+1;
    20     for(R int i=0;i<len;i++)
    21     {
    22         if(i<=MaxRight)
    23             RL[i]=min(RL[2*center-i],MaxRight-i);
    24         else RL[i]=1;
    25         while(s[i-RL[i]]==s[i+RL[i]] and i-RL[i]>=0 and i+RL[i]<len)
    26             RL[i]++;
    27         if(i+RL[i]-1>MaxRight)
    28             MaxRight=i+RL[i]-1,center=i;
    29     }
    30     for(R int i=0;i<len;i++)ans+=RL[i]/2;
    31     printf("%d",ans);
    32 }
    View Code

    我自己写的代码:

     1 #include <iostream>
     2 #include <string>
     3 #include <string.h>
     4 #include <algorithm>
     5 #include <vector>
     6 
     7 using namespace std;
     8 int sum;
     9 
    10 void Manacher(string s)
    11 {
    12     sum=0; 
    13     /*改造字符串*/
    14     string res="$#";
    15     for(int i=0;i<s.size();++i)
    16     {
    17         res+=s[i];
    18         res+="#";
    19     }
    20 
    21     /*数组*/
    22     vector<int> P(res.size(),0);
    23     int mi=0,right=0;   //mi为最大回文串对应的中心点,right为该回文串能达到的最右端的值
    24     int maxLen=0,maxPoint=0;    //maxLen为最大回文串的长度,maxPoint为记录中心点
    25 
    26     for(int i=1;i<res.size();++i)
    27     {
    28         //关键句,文中对这句以详细讲解
    29         if(right>i)
    30             P[i]=min(P[2*mi-i],right-i);
    31         else
    32             P[i]=1;
    33 //        P[i]=right>i ?min(P[2*mi-i],right-i):1; 
    34         
    35         while(res[i+P[i]]==res[i-P[i]])
    36             ++P[i];
    37         
    38         if(right<i+P[i])    //超过之前的最右端,则改变中心点和对应的最右端
    39         {
    40             right=i+P[i];
    41             mi=i;
    42         }
    43 
    44         if(maxLen<P[i])     //更新最大回文串的长度,并记下此时的点
    45         {
    46             maxLen=P[i];
    47             maxPoint=i;
    48         }
    49         sum+=P[i]/2;
    50     }
    51 //    return s.substr((maxPoint-maxLen)/2,maxLen-1); //要返回最长子串就把函数类型改为string
    52      printf("%d
    ",sum);
    53 }
    54 int main()
    55 {
    56     string str;
    57     cin>>str; 
    58     Manacher(str);
    59 }
    View Code

    思路二:

    回文自动机板子题,每次在LAST上CNT++,,最后从父亲累加儿子的CNT,因为如果fa[v]=u,则u一定是v的子回文串; 统计答案

     1 #include<set>
     2 #include<map>
     3 #include<ctime>
     4 #include<queue>
     5 #include<cmath>
     6 #include<cstdio>
     7 #include<vector>
     8 #include<cstring>
     9 #include<cstdlib>
    10 #include<iostream>
    11 #include<algorithm>
    12 #define ll unsigned long long
    13 #define mem(a,b) memset(a,b,sizeof(a))
    14 #define mec(a,b) memcpy(a,b,sizeof(b))
    15 using namespace std;
    16 const int  MAXN=1000+50;
    17 char str[MAXN];
    18 int len;
    19 ll ans;
    20 int hd[MAXN],ect;
    21 struct Edge{int nx,to,w;}ar[MAXN];
    22 void adds(int u,int v,int w){ar[++ect].to=v,ar[ect].w=w,ar[ect].nx=hd[u],hd[u]=ect;}
    23 struct  PAM
    24 {
    25     int tot,last,n;
    26     int fa[MAXN],ln[MAXN],s[MAXN],cnt[MAXN];
    27     void init()
    28     {
    29         fa[0]=fa[1]=1;
    30         ln[tot=1]=-1;ln[last=n=ect=0]=0;
    31         s[0]=-1;
    32     }
    33     int ge(int u,int w)
    34     {for(int e=hd[u],v=ar[e].to;e;v=ar[e=ar[e].nx].to)if(ar[e].w==w)return v;return 0;}
    35     int gf(int k){while(s[n-ln[k]-1]^s[n])k=fa[k];return k;}
    36     inline void extend(int x,int c)
    37     {
    38         s[++n]=c;last=gf(last);
    39         if(!ge(last,c))
    40         {
    41             fa[++tot]=ge(gf(fa[last]),c);
    42             ln[tot]=ln[last]+2;
    43             adds(last,tot,c);
    44 
    45         }
    46         cnt[last=ge(last,c)]++;
    47     }
    48     void calc()
    49     {
    50         for(int i=tot;i>=2;i--)
    51         {
    52             cnt[fa[i]]+=cnt[i];
    53             ans+=cnt[i];
    54         }
    55     }
    56 }pam;
    57 int main()
    58 {
    59 
    60     pam.init();
    61     scanf("%s",str+1);len=strlen(str+1);
    62     //for(int i=1;i<=len;i++)printf("%c",str[i]);
    63     for(int i=1,x;i<=len;i++)pam.extend(i,str[i]-'a');
    64     pam.calc();
    65     printf("%lld ",ans);
    66     return 0;
    67 
    68 }
    View Code

    思路三:

    利用回文树来写,回文树是一种处理回文串的强大工具

    推荐学习博客:
    回文树介绍(Palindromic Tree)

     1 #include <iostream>
     2 #include <string.h>
     3 #include <stdlib.h>
     4 #include <algorithm>
     5 #include <math.h>
     6 #include <stdio.h>
     7  
     8 using namespace std;
     9 #define MAX 1005
    10 struct Node
    11 {
    12     int next[26];
    13     int len;
    14     int sufflink;
    15     int num;
    16 }tree[MAX];
    17 char s[MAX];
    18  
    19 int num;
    20 int suff;
    21 bool addLetter(int pos)
    22 {
    23     int cur=suff,curlen=0;
    24     int let=s[pos]-'a';
    25  
    26     while(1)
    27     {
    28         curlen=tree[cur].len;
    29         if(pos-1-curlen>=0&&s[pos-1-curlen]==s[pos])
    30             break;
    31         cur=tree[cur].sufflink;
    32     }
    33     if(tree[cur].next[let])
    34     {
    35         suff=tree[cur].next[let];
    36         return false;
    37     }
    38     num++;
    39     suff=num;
    40     tree[num].len=tree[cur].len+2;
    41     tree[cur].next[let]=num;
    42     if(tree[num].len==1)
    43     {
    44         tree[num].sufflink=2;
    45         tree[num].num=1;
    46         return true;
    47     }
    48     while(1)
    49     {
    50         cur=tree[cur].sufflink;
    51         curlen=tree[cur].len;
    52         if(pos-1-curlen>=0&&s[pos-1-curlen]==s[pos])
    53         {
    54             tree[num].sufflink=tree[cur].next[let];
    55             break;
    56         }
    57     }
    58     tree[num].num=1+tree[tree[num].sufflink].num;
    59     return true;
    60  
    61 }
    62 void initTree()
    63 {
    64     num=2;suff=2;
    65     tree[1].len=-1;tree[1].sufflink=1;
    66     tree[2].len=0;tree[2].sufflink=1;
    67 }
    68 int main()
    69 {
    70     scanf("%s",s);
    71     int len=strlen(s);
    72     initTree();
    73     long long int ans=0;
    74     for(int i=0;i<len;i++)
    75     {
    76          addLetter(i);
    77          ans+=tree[suff].num;
    78     }
    79     printf("%d
    ",ans);
    80     return 0;
    81 }
    View Code

    看看上一题的升级版

    The Number of Palindromes

    题意:

    给出一个字符串,求其不相同回文子串的个数

    思路一:

    回文自动机模板题,因为回文自动机中每个新建的结点就表示一个回文子串,各个结点都不相同
    所以不同回文子串个数就是回文自动机中新增结点个数,直接输出即可

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int MAXN = 100005 ;
     5 const int N = 26 ;
     6 typedef long long LL;
     7 struct Palindromic_Tree {
     8     int next[MAXN][N] ;//next指针,next指针和字典树类似,指向的串为当前串两端加上同一个字符构成
     9     int fail[MAXN] ;//fail指针,失配后跳转到fail指针指向的节点
    10     LL cnt[MAXN] ; //表示节点i表示的本质不同的串的个数(建树时求出的不是完全的,最后count()函数跑一遍以后才是正确的)
    11     int num[MAXN] ; //表示以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数
    12     int len[MAXN] ;//len[i]表示节点i表示的回文串的长度(一个节点表示一个回文串)
    13     int S[MAXN] ;//存放添加的字符
    14     int last ;//指向新添加一个字母后所形成的最长回文串表示的节点。
    15     int n ;//表示添加的字符个数。
    16     int p ;//表示添加的节点个数。
    17 
    18     int newnode ( int l ) {//新建节点
    19         for ( int i = 0 ; i < N ; ++ i ) next[p][i] = 0 ;
    20         cnt[p] = 0 ;
    21         num[p] = 0 ;
    22         len[p] = l ;
    23         return p ++ ;
    24     }
    25 
    26     void init () {//初始化
    27         p = 0 ;
    28         newnode (  0 ) ;
    29         newnode ( -1 ) ;
    30         last = 0 ;
    31         n = 0 ;
    32         S[n] = -1 ;//开头放一个字符集中没有的字符,减少特判
    33         fail[0] = 1 ;
    34     }
    35 
    36     int get_fail ( int x ) {//和KMP一样,失配后找一个尽量最长的
    37         while ( S[n - len[x] - 1] != S[n] ) x = fail[x] ;
    38         return x ;
    39     }
    40 
    41     void add ( int c ) {
    42         c -= 'a' ;
    43         S[++ n] = c ;
    44         int cur = get_fail ( last ) ;//通过上一个回文串找这个回文串的匹配位置
    45         if ( !next[cur][c] ) {//如果这个回文串没有出现过,说明出现了一个新的本质不同的回文串
    46             int now = newnode ( len[cur] + 2 ) ;//新建节点
    47             fail[now] = next[get_fail ( fail[cur] )][c] ;//和AC自动机一样建立fail指针,以便失配后跳转
    48             next[cur][c] = now ;
    49             num[now] = num[fail[now]] + 1 ;
    50         }
    51         last = next[cur][c] ;
    52         cnt[last] ++ ;
    53     }
    54 
    55     void count () {
    56         for ( int i = p - 1 ; i >= 0 ; -- i ) cnt[fail[i]] += cnt[i] ;
    57         //父亲累加儿子的cnt,因为如果fail[v]=u,则u一定是v的子回文串!
    58     }
    59 }T;
    60 
    61 int main()
    62 {
    63     std::ios::sync_with_stdio(false);
    64     string a;
    65     int t;
    66     int ct=1;
    67     cin>>t;
    68     while(t--)
    69     {
    70         cin>>a;
    71         T.init();
    72         int len=a.size();
    73         for(int i=0;i<len;i++)
    74             T.add(a[i]);
    75         cout<<"Case #"<<ct++<<": ";
    76         cout<<T.p-2<<endl;     //输出新增结点个数即可
    77     }
    78 }
    View Code

    思路二:

    后缀数组+马拉车(本质不同回文子串统计)

    回文子串可以考虑先来个O(n)的马拉车预处理,这样每个回文子串长度必然是计数,那么我们可以统计本质不同的(正中间的字符+右半边串)回文子串个数。然后可以考虑用后缀自动机统计答案。这道题的关键的关键在于去重的处理。去重要求去掉:h[i]范围内已经被统计过的串。那么可以用一个变量维护 目前已经被统计过的长度。要注意到h数组和马拉车的lc数组是没什么关系的。

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define rank rk
      4 const int MAX = 2e5+10000;
      5 char ch[MAX];
      6 int cntA[MAX],cntB[MAX],A[MAX],B[MAX],tsa[MAX],rank[MAX],SA[MAX],lc[MAX],h[MAX];
      7 int n,t;
      8 int Cas =1; 
      9 void init(){
     10     memset(ch,0,sizeof ch);
     11     ch[0]='z'+1;
     12 }
     13 void input(){
     14     scanf("%s",ch+1);
     15     n =  strlen(ch+1);
     16     ch[n*2+1]='#';
     17     for (int i=n;i>=1;i--){
     18         ch[i*2] = ch[i];
     19         ch[i*2-1] ='#';
     20     }
     21     n = n*2+1;
     22     ch[n+1]='';
     23 }
     24 void get_SA(){
     25     for (int i=0;i<=10000;i++) cntA[i]=0;
     26     for (int i=1;i<=n;i++) cntA[ch[i]]++;
     27     for (int i=1;i<=10000;i++) cntA[i]+=cntA[i-1];
     28     for (int i=n;i>=1;i--) SA[cntA[ch[i]]--] =i;
     29     rank[SA[1]]=1;
     30     for (int i=2;i<=n;i++){
     31         rank[SA[i]]=rank[SA[i-1]];
     32         if (ch[SA[i]]!=ch[SA[i-1]]) rank[SA[i]]++;
     33     }
     34     for (int step = 1;rank[SA[n]]<n;step<<=1){
     35         for (int i=0;i<=n;i++)cntA[i]=cntB[i]=0;
     36         for (int i=1;i<=n;i++){
     37             cntA[A[i]=rank[i]]++;
     38             cntB[B[i]=(i+step<=n)?rank[i+step]:0]++;
     39         }
     40         for (int i=1;i<=n;i++) cntA[i]+=cntA[i-1],cntB[i]+=cntB[i-1];
     41         for (int i=n;i>=1;i--) tsa[cntB[B[i]]--] =i;
     42         for (int i=n;i>=1;i--) SA[cntA[A[tsa[i]]]--] = tsa[i];
     43         rank[SA[1]]=1;
     44         for (int i=2;i<=n;i++){
     45             rank[SA[i]]=rank[SA[i-1]];
     46             if (A[SA[i]]!=A[SA[i-1]]||B[SA[i]]!=B[SA[i-1]]) rank[SA[i]]++;
     47         }
     48     }
     49 }
     50 void get_Height(){
     51     for (int i=1,j=0;i<=n;i++){
     52         if (j) j--;
     53         while (ch[i+j]==ch[SA[rank[i]-1]+j])j++;
     54         h[rank[i]]=j;
     55     }
     56 }
     57 void Manacher(){
     58     lc[1]=1;
     59     int k=1;
     60     for (int i=2;i<=n;i++){
     61 //        printf("%d %d
    ",i,k);
     62         int p = k+lc[k]-1;
     63         if (i<=p){
     64             lc[i]=min(lc[2*k-i],p-i+1);
     65         }else{
     66             lc[i]=1;
     67         }
     68         while (ch[i+lc[i]]==ch[i-lc[i]])lc[i]++;
     69         if (i+lc[i]>k+lc[k])k=i;
     70     }
     71 }
     72 void print(){
     73     printf("%s
    ",ch+1);
     74     for (int i=1;i<=n;i++){
     75         printf("%s %d
    ",ch+SA[i],lc[SA[i]]);
     76     }
     77 }
     78 void solve(){
     79     get_SA();
     80     get_Height();
     81     Manacher();
     82     print();
     83     long long res =0;
     84 //    cout<<"1: "<<res<<endl;
     85     int cnt=0;
     86     for (int i=2;i<=n;i++){
     87         cnt = min(cnt,h[i]);
     88         res+=max(0,lc[SA[i]]-min(h[i],cnt));
     89   //      cout<<i<<" "<<res<<endl;
     90         if (lc[SA[i]]>cnt){
     91             cnt = lc[SA[i]];
     92         }
     93     }
     94 //    cout<<res/2<<endl;
     95     printf("Case #%d: %I64d
    ",Cas++,res/2);
     96 }
     97 int main(){
     98     scanf("%d",&t);
     99     while (t--){
    100         init();
    101         input();
    102         solve();
    103     }
    104     return 0;
    105 }
    View Code
    这道题主要是去重。
      一开始我打的去重还是很有问题,还是看别人的才打出来了。
      
      把原串反向加入到原串后面,中间插入特殊字符。后缀数组求sa、height。
      分奇偶,奇串和偶串肯定是不同种的。然后对于一个位置i,找到对应位置,用rmq求区间min。
      去重:用cnt记录目前计算的回文长度与height的min值(所以这里计算的时候要按字符串大小顺序计算)。
      如果有新增回文串,就加进去,并更新cnt
     
      主要是最后一步,要好好理解。
      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<algorithm>
      6 #include<queue>
      7 using namespace std;
      8 #define Maxl 200010
      9 #define INF 0xfffffff
     10 
     11 int c[Maxl];
     12 int n,cl,l;
     13 
     14 int mymin(int x,int y) {return x<y?x:y;}
     15 int mymax(int x,int y) {return x>y?x:y;}
     16 
     17 char s[Maxl];
     18 void init()
     19 {
     20     scanf("%s",s);
     21     l=strlen(s);cl=0;
     22     for(int i=0;i<l;i++) c[++cl]=s[i]-'a'+1;
     23     c[++cl]=30;
     24     for(int i=l-1;i>=0;i--) c[++cl]=s[i]-'a'+1;
     25 }
     26 
     27 int sa[Maxl],rk[Maxl],Rs[Maxl],y[Maxl],wr[Maxl];
     28 void get_sa(int m)
     29 {
     30     memcpy(rk,c,sizeof(rk));
     31     for(int i=0;i<=m;i++) Rs[i]=0;
     32     for(int i=1;i<=cl;i++) Rs[rk[i]]++;
     33     for(int i=1;i<=m;i++) Rs[i]+=Rs[i-1];
     34     for(int i=cl;i>=1;i--) sa[Rs[rk[i]]--]=i;
     35     
     36     int ln=1,p=0;//p表示目前有多少个不一样的rk
     37     while(p<cl)
     38     {
     39         int k=0;
     40         for(int i=cl-ln+1;i<=cl;i++) y[++k]=i;
     41         for(int i=1;i<=cl;i++) if(sa[i]>ln) y[++k]=sa[i]-ln;
     42         for(int i=1;i<=cl;i++) 
     43             wr[i]=rk[y[i]];
     44         
     45         for(int i=0;i<=m;i++) Rs[i]=0;
     46         for(int i=1;i<=cl;i++) Rs[wr[i]]++;
     47         for(int i=1;i<=m;i++) Rs[i]+=Rs[i-1];
     48         for(int i=cl;i>=1;i--) sa[Rs[wr[i]]--]=y[i];
     49         
     50         for(int i=1;i<=cl;i++) wr[i]=rk[i];
     51         for(int i=cl+1;i<=cl+ln;i++) wr[i]=0;
     52         p=1,rk[sa[1]]=1;
     53         for(int i=2;i<=cl;i++)
     54         {
     55             if(wr[sa[i]]!=wr[sa[i-1]]||wr[sa[i]+ln]!=wr[sa[i-1]+ln]) p++;
     56             rk[sa[i]]=p;
     57         }
     58         ln*=2;m=p;
     59     }
     60     sa[0]=rk[0]=0;
     61 }
     62 
     63 int height[Maxl];
     64 void get_he()
     65 {
     66     int k=0;
     67     for(int i=1;i<=cl;i++) if(rk[i]!=1)
     68     {
     69         int j=sa[rk[i]-1];
     70         if(k) k--;
     71         while(c[i+k]==c[j+k]&&i+k<=cl&&j+k<=cl) k++;
     72         height[rk[i]]=k;
     73     }
     74     height[1]=0;
     75 }
     76 
     77 int d[Maxl][20];
     78 void rmq_init()
     79 {
     80     for(int i=1;i<=cl;i++) d[i][0]=height[i];
     81     for(int j=1;(1<<j)<=cl;j++)
     82       for(int i=1;i+(1<<j)-1<=cl;i++)
     83         d[i][j]=mymin(d[i][j-1],d[i+(1<<j-1)][j-1]);
     84 }
     85 
     86 int rmq(int x,int y)
     87 {
     88     int t;
     89     if(x>y) t=x,x=y,y=t;
     90     x++;
     91     int k=0;
     92     while((1<<(k+1))<=y-x+1) k++;
     93     return mymin(d[x][k],d[y-(1<<k)+1][k]);
     94 }
     95 
     96 
     97 int ans;
     98 void ffind()
     99 {
    100     int cnt=0;ans=0;
    101     //
    102     for(int i=1;i<=cl-n;i++)
    103     {
    104         cnt=mymin(cnt,height[i]);
    105         if(sa[i]<=l)
    106         {
    107             int j=rk[cl-sa[i]+1];
    108             int tem=rmq(i,j);
    109             if(tem>cnt)
    110             {
    111                 ans+=(tem-cnt);
    112                 cnt=tem;
    113             }
    114         }
    115     }
    116     //
    117     cnt=0;
    118      for(int i=1;i<=cl-n;i++)
    119      {
    120         cnt=mymin(cnt,height[i]);
    121         if(sa[i]<=l)
    122         {
    123             int j=rk[cl-sa[i]+2];
    124             int tem=rmq(i,j);
    125             if(tem>cnt)
    126             {
    127                 ans+=tem-cnt;
    128                 cnt=tem;
    129             }
    130         }
    131      }
    132 }
    133 
    134 int main()
    135 {
    136     int T,kase=0;
    137     scanf("%d",&T);
    138     while(T--)
    139     {
    140         init();
    141         get_sa(30+n);
    142         get_he();
    143         rmq_init();
    144         ffind();
    145         printf("Case #%d: %d
    ",++kase,ans);
    146     }
    147     return 0;
    148 }
    149 
    150 [HDU3948]
    View Code

    思路三:

    回文树模板,学一学贴一贴啊...

     1 #define me AcrossTheSky&HalfSummer11 
     2 #include <cstdio> 
     3 #include <cmath> 
     4 #include <ctime> 
     5 #include <string> 
     6 #include <cstring> 
     7 #include <cstdlib> 
     8 #include <iostream> 
     9 #include <algorithm> 
    10    
    11 #include <set>
    12 #include <stack> 
    13 #include <queue> 
    14 #include <vector> 
    15    
    16 #define lowbit(x) (x)&(-x) 
    17 #define Abs(x) ((x) > 0 ? (x) : (-(x))) 
    18 #define FOR(i,a,b) for((i)=(a);(i)<=(b);(i)++) 
    19 #define FORP(i,a,b) for(int i=(a);i<=(b);i++) 
    20 #define FORM(i,a,b) for(int i=(a);i>=(b);i--) 
    21 #define ls(a,b) (((a)+(b)) << 1) 
    22 #define rs(a,b) (((a)+(b)) >> 1) 
    23 #define getlc(a) ch[(a)][0] 
    24 #define getrc(a) ch[(a)][1] 
    25    
    26 #define maxn 100005
    27 #define maxc 30
    28 #define maxm 100005
    29 #define INF 1070000000 
    30 using namespace std; 
    31 typedef long long ll; 
    32 typedef unsigned long long ull; 
    33    
    34 template<class T> inline 
    35 void read(T& num){ 
    36     num = 0; bool f = true;char ch = getchar(); 
    37     while(ch < '0' || ch > '9') { if(ch == '-') f = false;ch = getchar();} 
    38     while(ch >= '0' && ch <= '9') {num = num * 10 + ch - '0';ch = getchar();} 
    39     num = f ? num: -num; 
    40 }
    41 int outs[100];
    42 template<class T> inline
    43 void write(T x){
    44     if (x==0) {putchar('0'); putchar('
    '); return;}
    45     if (x<0) {putchar('-'); x=-x;}
    46     int num=0;
    47     while (x){ outs[num++]=(x%10); x=x/10;}
    48     FORM(i,num-1,0) putchar(outs[i]+'0'); putchar('
    ');
    49 }
    50 /*==================split line==================*/
    51 int tot[maxn],num[maxn],len[maxn],fail[maxn],S[maxn],ch[maxn][maxc];
    52 char s[maxn];
    53 int p,last,ans,cnt;
    54 int newnode(int l){
    55     tot[p]=0; num[p]=0; len[p]=l;
    56     return p++;
    57 }
    58 void init(){
    59     p=0; memset(ch,0,sizeof(ch));
    60     newnode(0); newnode(-1);
    61     last=0; cnt=0; S[cnt]=-1; fail[0]=1;
    62 }
    63 int get_fail(int x){
    64     while(S[cnt-len[x]-1]!=S[cnt]) x=fail[x];
    65     return x;
    66 }
    67 void add(int c,int pos){
    68     S[++cnt]=c;
    69     int cur=get_fail(last);
    70     if (!ch[cur][c]){
    71         int now=newnode(len[cur]+2);
    72         fail[now]=ch[get_fail(fail[cur])][c];
    73         ch[cur][c]=now; ans++;
    74     }
    75     last=ch[cur][c];
    76     tot[last]++;
    77 }
    78 int main(){
    79     int cas; read(cas); int Cas=1;
    80     while (Cas<=cas){
    81         printf("Case #%d: ",Cas);
    82         ans=0;
    83         scanf("%s",s);
    84         int n=strlen(s);
    85         init();
    86         FORP(i,0,n-1) add(s[i]-'a'+1,i);
    87         write(ans);
    88         Cas++;
    89     }
    90 }
    View Code
  • 相关阅读:
    「杂文」随想录
    「小说」妖精舞于废墟之上
    昨日之盛,明日之俗 ~ SDOI2021 退役记
    P6292 区间本质不同子串个数
    「杂文」生之重
    「闭门造车」二叉分块树
    「杂文」雨色的魔法(一)
    「笔记」斜率优化 DP
    「笔记」后缀数组
    NOIP 2020 AFO 记
  • 原文地址:https://www.cnblogs.com/jiamian/p/11252214.html
Copyright © 2011-2022 走看看