【HDU3948】 The Number of Palindromes (后缀数组+RMQ)
The Number of Palindromes
Problem DescriptionNow, you are given a string S. We want to know how many distinct substring of S which is palindrome.InputThe first line of the input contains a single integer T(T<=20), which indicates number of test cases.
Each test case consists of a string S, whose length is less than 100000 and only contains lowercase letters.OutputFor every test case, you should output "Case #k:" first in a single line, where k indicates the case number and starts at 1. Then output the number of distinct substring of S which is palindrome.
Sample Input3aaaaabababcdSample OutputCase #1: 4Case #2: 4Case #3: 4
【题意】
统计一个字符串内有多少个不同的回文串。
【分析】
这道题主要是去重。
一开始我打的去重还是很有问题,还是看别人的才打出来了。
把原串反向加入到原串后面,中间插入特殊字符。后缀数组求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 }
2016-07-19 09:46:16