求回文串个数

先整理各路大神的题解 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 }

我自己写的代码:

 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\n",sum);
53 }
54 int main()
55 {
56     string str;
57     cin>>str;
58     Manacher(str);
59 }

思路二:

回文自动机板子题,每次在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 }

思路三:

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

推荐学习博客:
回文树介绍(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\n",ans);
80     return 0;
81 }



看看上一题的升级版

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 }

思路二:

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

回文子串可以考虑先来个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]=‘\0‘;
 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\n",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\n",ch+1);
 74     for (int i=1;i<=n;i++){
 75         printf("%s %d\n",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\n",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 }

这道题主要是去重。

  一开始我打的去重还是很有问题,还是看别人的才打出来了。

  

  把原串反向加入到原串后面,中间插入特殊字符。后缀数组求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\n",++kase,ans);
146     }
147     return 0;
148 }
149
150 [HDU3948]

思路三:

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

 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(‘\n‘); 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(‘\n‘);
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 }

原文地址:https://www.cnblogs.com/jiamian/p/11252214.html

时间: 2024-10-06 00:11:06

求回文串个数的相关文章

马拉车,O(n)求回文串

body { font-family: sans-serif; font-size: 14px; line-height: 1.6; padding-top: 10px; padding-bottom: 10px; background-color: white; padding: 30px } body>*:first-child { margin-top: 0 !important } body>*:last-child { margin-bottom: 0 !important } a

Palindrome - URAL - 1297(求回文串)

题目大意:RT 分析:后缀数组求回文串,不得不说确实比较麻烦,尤其是再用线段数进行查询,需要注意的细节地方比较多,比赛实用性不高......不过练练手还是可以的. 线段数+后缀数组代码如下: =========================================================================================================================================== #include<stdio

HDU 5371(2015多校7)-Hotaru&#39;s problem(Manacher算法求回文串)

题目地址:HDU 5371 题意:给你一个具有n个元素的整数序列,问你是否存在这样一个子序列,该子序列分为三部分,第一部分与第三部分相同,第一部分与第二部分对称,如果存在求最长的符合这种条件的序列. 思路:用Manacher算法来处理回文串的长度,记录下以每一个-1(Manacher算法的插入)为中心的最大回文串的长度.然后从最大的开始穷举,只要p[i]-1即能得出以数字为中心的最大回文串的长度,然后找到右边对应的'-1',判断p[i]是不是大于所穷举的长度,如果当前的满足三段,那么就跳出,继续

马拉车——最长回文子串长度、回文串个数

题目链接 模板 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=3e5+5; 4 5 char s[maxn],str[maxn]; 6 int l1,l2,p[maxn],ans; 7 8 void init() 9 { 10 str[0]='$'; 11 str[1]='#'; 12 for(int i=0;i<l1;i++) 13 { 14 str[i*2+2]=s[i]; 15 str[i*2+3

马拉车算法——求回文子串个数zoj4110

zoj的测评姬好能卡时间.. 求回文子串的个数:只要把p[i]/2就行了: 如果s_new[i]是‘#’,算的是没有中心的偶回文串 反之是奇回文串 /* 给定两个字符串s,t 结论:s,t不相同的第一个字符下标为l,最后一个字符下标为r 如果l==r,那么不存在解 如果l<r,那么翻转s的一个子串时,一定是将s[l]和s[r]互相翻转 反证:假设存在s[l]和s[r+k]的翻转方法, 因为s[r+k]=t[r+k]=t[l],且s[l]=t[r+k],可得s[l]=t[l],矛盾 l-k同理 所

[haoi2009]求回文串

所谓回文串,就是对于给定的字符串,正着读和反着读都一样,比如ABCBA就是一个回文串,ABCAB则不是.我们的目标是对于任意输入的字符串,不断将第i个字符和第i+1个字符交换,使得该串最终变为回文串.求最少交换次数. 题解: 有一种做法是贪心: 就是每次找到最左端的字符,然后找到这序列中最右边的一样的字符,然后把这个字符移过去,然后把最左端右移,继续以上操作: 最后的答案就是每次的移动步数加起来: 要吐槽的是,window下I64d不要忘了...... #include<iostream> #

Codeforces Round #427 (Div. 2) D. Palindromic characteristics(Manacher求回文串)

题目链接:Codeforces Round #427 (Div. 2) D. Palindromic characteristics 题意: 给你一个串,定义k-th回文串,让你求每个k-th的数量. 题解: manacher处理好后做一下dp就行了. 当然也可以直接dp不用manacher. 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;++i) 3 using namespace std; 4 5 cons

HDU 1513 Palindrome 求回文串

这个题是走弯路了,刚开始自己DP出了方程,无限MLE,唉 if(s1[i]==s1[j]) dp[i][j]=dp[i+1][j-1]; else dp[i][j]=min(dp[i][j-1],dp[i+1][j]) +1; 后来百度了一下,这个原来是个经典回文串问题,即先将串置反,然后求LCS........ 然后就是这题卡时间卡的特别厉害,多用了一次strlen就TLE AC: #include<cstdio> #include<string> #include<str

hihocoder 1032 manachar 求回文串O(n)

#include <cstdio> #include <iostream> #include <algorithm> #include <queue> #include <cmath> #include <cstring> #include <stack> #include <set> #include <map> #include <vector> using namespace st