hdu 3948
1 /* 2 题意:给你一个串,求该串的不同子回文串的个数; 3 4 分析:首先我们想一下一个比较简单的问,求一个串的不同子串的个数 5 显然每个子串都是一个后缀的前缀,那么只要按照SA[]统计该后缀i的前缀 6 有那些是出现过的,也就是ans+=len[该后缀长]-height[i]; 7 8 9 同样的道理,我们先统计出以i为中心的回文串到最右边的距离,然后 10 再统计不同回文串的个数,即减去相同回文串的个数,但是两者还是有区别的 11 其次,为了统一奇偶的差别,我们构造出另一个字符串, 12 s1=aabaa -> s=$#a#a#b#a#a# (可以参看本博客前前篇文章MANACHER) 13 首先我用MANACHER的预处理出以s[i]为中心的回文串到最右边的距离记录在lc[i]; 14 当然可以直接用后缀数组的方法求出(将反串加在原串后面,然后询问后缀i和后缀2*n-i的LCP,但要分奇偶) 15 16 统计不同子串个数和统计不同回文串的个数的区别 17 看样例:aabaa 18 19 20 构造的串:$#a#a#b#a#a# 21 后缀 lc[i] 回文串的个数 22 11 1 # 1 23 9 3 #a# 3 24 7 1 #a#a# 1 25 1 1 #a#a#b#a#a# 1 26 3 3 #a#b#a#a# 3 & 27 5 1 #b#a#a# 1 28 29 0 1 $#a#a#b#a#a# 1 30 10 2 a# 2 31 8 2 a#a# 2 32 2 2 a#a#b#a#a# 2 33 4 2 a#b#a#a# 2 34 6 6 b#a#a# 6 35 36 先不考虑加入#后产生的回文串, 37 在统计后缀3中包含的回文串时,会把#a,和#a#统计进去,但我们发现在统计后缀9时#a,#a#就已经被统计了 38 也就是说统计后缀i中已经被统计过的回文串的个数,不一定只是后缀i-1中的回文,还有可能是更前面的, 39 所以我们在遍历的过程中设置一个标记tmp,表示以字符i为中点能延伸的最长距离,而不是该串在原串中能延伸的距离 40 41 至于加入#后多出了的回文串,可以发现不管是lc[]还是height[]长度都是延伸到#位置的也就是相减后/2就是原串的个数 42 还有加进了#最后答案要减去1; 43 44 */ 45 #include<cstdio> 46 #include<cstring> 47 #include<cstdlib> 48 #include<iostream> 49 #include<algorithm> 50 #include<cmath> 51 #include<vector> 52 using namespace std; 53 typedef long long LL; 54 const int N=200000+10; 55 char s[N],s1[N]; 56 struct SuffixArray{ 57 int a1[N],a2[N],c[N],SA[N],sa[N],*rank,*x,*y; 58 int n,height[N],m; 59 void sort(){ 60 for (int i=0;i<m;i++) c[i]=0; 61 for (int i=0;i<n;i++) c[x[i]]++; 62 for (int i=0;i<m;i++) c[i+1]+=c[i]; 63 for (int i=n-1;i>=0;i--) SA[ --c[x[sa[i]]] ] = sa[i]; 64 } 65 void build_sa(char *s){ 66 n=strlen(s); m=256; 67 x=a1; y=a2; x[n]=y[n]=-1; 68 for (int i=0;i<n;i++) x[i]=s[i],sa[i]=i; 69 sort(); 70 for (int k=1;k<=n;k<<=1){ 71 int p=0; 72 for (int i=n-k;i<n;i++) sa[p++]=i; 73 for (int i=0;i<n;i++) if (SA[i]>=k) sa[p++]=SA[i]-k; 74 sort(); 75 p=0; swap(x,y); 76 x[SA[0]]=0; 77 for (int i=1;i<n;i++){ 78 if ( y[ SA[i-1] ]!=y[ SA[i] ] || y[ SA[i-1]+k ]!=y[ SA[i]+k ] ) p++; 79 x[SA[i]]=p; 80 } 81 if (p+1==n) break; 82 m=p+1; 83 } 84 rank=x; getHeight(s); 85 } 86 void getHeight(char *s){ 87 int k=0; 88 for (int i=0;i<n;i++){ 89 if (k) k--; 90 if (rank[i]==0) continue; 91 int j=SA[ rank[i]-1 ]; 92 while (i+k<n && j+k<n && s[i+k]==s[j+k]) k++; 93 height[rank[i]]=k; 94 } 95 height[n]=0; 96 } 97 }H; 98 int lc[N*2]; 99 int lx[N],ly[N]; 100 void init(char *s1){ 101 int c=0; 102 int n=strlen(s1); 103 s[c++]='$';s[c++]='#'; 104 for (int i=0;s1[i];i++){ 105 s[c++]=s1[i]; 106 s[c++]='#'; 107 }s[c]='\0'; 108 lc[0]=1;lc[1]=1; 109 int k=1; 110 for (int i=2;i<c;i++){ 111 int p=k+lc[k]-1; 112 if (i>=p){ 113 int j=0; 114 while (i-j>=0 && i+j<c && s[i-j]==s[i+j]) j++; 115 lc[i]=j; k=i; 116 }else { 117 int j=2*k-i; 118 if (i+lc[j]-1<p) lc[i]=lc[j]; 119 else { 120 int d=p-i+1; 121 while (i-d>=0 && i+d<c && s[i-d]==s[i+d]) d++; 122 lc[i]=d; k=i; 123 } 124 } 125 } 126 127 } 128 void solve(){ 129 int n=strlen(s); 130 int ret=lc[H.SA[0]]; 131 int tmp=lc[H.SA[0]]; 132 // cout<<s<<endl; 133 134 // cout<<H.SA[0]<<" "<<lc[H.SA[0]]<<" "<<s+H.SA[0]<<endl; 135 for (int i=1;i<n;i++){ 136 int t=H.SA[i]; 137 // cout<<H.SA[i]<<" "<<lc[H.SA[i]]<<" "<<s+H.SA[i]<<endl; 138 ret+=max(0,(lc[t]-min(H.height[i],tmp))/2);//tmp表示以字符s[H.SA[i-1]]为中心已经被统计过的回文串的个数 139 if (lc[t]>=tmp) tmp=lc[t]; 140 else { 141 tmp=min(tmp,H.height[i]);//从上一个传递到当前; 142 if (lc[t]>tmp) tmp=lc[t];//如果该后缀本身的回文个数更多久更新; 143 } 144 } 145 printf("%d\n",ret-1); 146 } 147 int main(){ 148 int T,cas=0; 149 scanf("%d",&T); 150 while (T--){ 151 scanf("%s",s1); 152 init(s1); 153 H.build_sa(s); 154 printf("Case #%d: ",++cas); 155 solve(); 156 } 157 return 0; 158 } 159 /* 160 6 161 abba 162 baab 163 aabaa 164 aaaa 165 abab 166 abcd 167 168 169 */
hdu 3518
1 /* 2 题意:统计一个字符串里不错至少2次且不覆盖的子串的个数 3 4 后缀数组求出height后,枚举子串的长度L,利用L对height分组 5 对于同一组里的后缀,如果在组里最小后缀和最大后缀的差大于L就说明至少有俩个长度为L串 6 且不覆盖的出现,所以ans++; 7 8 为什么这样不会重复统计,假设长度为L的字串s1是满足要求的串 9 让我们看一下长度为L的子串s1是如何被统计进去的, 10 首先我们知道所有前缀是s1的后缀在SA[]数组里将连续出现,而且相邻的height[]>=L; 11 也就是说只要其中俩个后缀的距离大于等于L就说明他们不重叠; 12 所以串s1只会被统计一次; 13 时间复杂度是o(n^2); 14 15 */ 16 #include<cstdio> 17 #include<cstdlib> 18 #include<cstring> 19 #include<iostream> 20 #include<algorithm> 21 #include<vector> 22 using namespace std; 23 const int N=1000+10; 24 struct SuffixArray{ 25 int a1[N],a2[N],c[N],SA[N],sa[N],*rank,*x,*y; 26 int n,height[N],m; 27 void sort(){ 28 for (int i=0;i<m;i++) c[i]=0; 29 for (int i=0;i<n;i++) c[x[i]]++; 30 for (int i=0;i<m;i++) c[i+1]+=c[i]; 31 for (int i=n-1;i>=0;i--) SA[ --c[x[sa[i]]] ] = sa[i]; 32 } 33 void build_sa(char *s){ 34 n=strlen(s); m=256; 35 x=a1;y=a2; x[n]=y[n]=-1; 36 for (int i=0;i<n;i++) x[i]=s[i],sa[i]=i; 37 sort(); 38 for (int k=1;k<=n;k<<=1){ 39 int p=0; 40 for (int i=n-k;i<n;i++) sa[p++]=i; 41 for (int i=0;i<n;i++) if (SA[i]>=k) sa[p++]=SA[i]-k; 42 sort(); 43 p=0; swap(x,y); 44 x[SA[0]]=0; 45 for (int i=1;i<n;i++){ 46 if (y[ SA[i-1] ]!=y[ SA[i] ] || y[ SA[i-1]+k ]!=y[ SA[i]+k ] ) p++; 47 x[SA[i]]=p; 48 } 49 if (p+1==n) break; 50 m=p+1; 51 } 52 rank=x;getHeight(s); 53 } 54 void getHeight(char *s){ 55 int k=0; 56 for (int i=0;i<n;i++){ 57 if (k) k--; 58 if (rank[i]==0) continue; 59 int j=SA[ rank[i]-1 ]; 60 while (i+k<n && j+k<n && s[i+k]==s[j+k]) k++; 61 height[ rank[i] ]=k; 62 } 63 height[n]=0; 64 } 65 }H; 66 char s[N]; 67 vector<int > g; 68 void solve(){ 69 int ret=0; 70 int n=strlen(s); 71 /* cout<<">.<"<<endl; 72 for (int i=0;i<n;i++) cout<<H.SA[i]<<" ";cout<<endl; 73 for (int i=0;i<n;i++) cout<<H.rank[i]<<" ";cout<<endl; 74 for (int i=1;i<n;i++)cout<<H.height[i]<<" ";cout<<endl; 75 cout<<">.<"<<endl; 76 */ for (int i=n/2;i>=1;i--){ 77 g.clear(); 78 for (int j=1;j<=n;j++){ 79 if (H.height[j]>=i){ 80 g.push_back(H.SA[j-1]); 81 }else { 82 g.push_back(H.SA[j-1]); 83 sort(g.begin(),g.end()); 84 int sz=g.size(); 85 if (sz>1 && g[sz-1]-g[0]>=i) ret++; 86 g.clear(); 87 } 88 } 89 90 } 91 printf("%d\n",ret); 92 } 93 int main(){ 94 while (~scanf("%s",&s)){ 95 if (s[0]=='#') break; 96 H.build_sa(s); 97 solve(); 98 } 99 return 0; 100 } 101 /* 102 aaaa 103 ababcabb 104 aaaaaa 105 # 106 107 */
hdu 4416
1 /* 2 题意:求出现在s串中,但不出现在其他n个串中的字串个数; 3 4 类似统计求一个串中不同的子串个数; 5 6 我的做法是,先链接这些串,定义起点在s中的后缀叫目标后缀; 7 求从前往后,从后往前扫两边,求出每一个目标后缀在SA[]数组中前后 8 最近的非目标后缀和其的LCP,Lx[]中保存的是两个中的较大值; 9 因为有可能多个目标后缀在SA[]数组中是连续的,所以还要减去其中一部分 10 比如 11 2 bab 12 0 babab 13 1 babac 14 3 babd 15 0,1都是目标后缀,2,3都是非目标后缀,那么0,1后缀的非法子串是bab 16 有因为0,1后缀相邻,要减去(height[]-lx[]); 17 所以在统计的时候baba才只被统计一次, 18 19 那么剩下的就是要求的串的个数, 20 */ 21 #include<cstdio> 22 #include<cstring> 23 #include<iostream> 24 #include<algorithm> 25 #include<cmath> 26 #include<cstdlib> 27 #include<vector> 28 using namespace std; 29 typedef long long LL; 30 const int N=300000+10; 31 struct SuffixArray{ 32 int a1[N],a2[N],c[N],SA[N],sa[N],*rank,*x,*y; 33 int n,height[N],m; 34 void sort(){ 35 for (int i=0;i<m;i++) c[i]=0; 36 for (int i=0;i<n;i++) c[x[i]]++; 37 for (int i=0;i<m;i++) c[i+1]+=c[i]; 38 for (int i=n-1;i>=0;i--) SA[ --c[x[sa[i]]] ] = sa[i]; 39 } 40 void build_sa(char *s){ 41 n=strlen(s); m=256; 42 x=a1; y=a2; x[n]=y[n]=-1; 43 for (int i=0;i<n;i++) x[i]=s[i],sa[i]=i; 44 sort(); 45 for (int k=1;k<=n;k<<=1){ 46 int p=0; 47 for (int i=n-k;i<n;i++) sa[p++]=i; 48 for (int i=0;i<n;i++) if (SA[i]>=k) sa[p++]=SA[i]-k; 49 sort(); 50 p=0; swap(x,y); 51 x[SA[0]]=0; 52 for (int i=1;i<n;i++){ 53 if ( y[ SA[i-1] ]!=y[ SA[i] ] || y[ SA[i-1]+k ]!=y[ SA[i]+k ] ) p++; 54 x[SA[i]]=p; 55 } 56 if (p+1==n) break; 57 m=p+1; 58 } 59 rank=x; getHeight(s); 60 } 61 void getHeight(char *s){ 62 int k=0; 63 for (int i=0;i<n;i++){ 64 if (k) k--; 65 if (rank[i]==0) continue; 66 int j=SA[ rank[i]-1 ]; 67 while (i+k<n && j+k<n && s[i+k]==s[j+k]) k++; 68 height[rank[i]]=k; 69 } 70 height[n]=0; 71 } 72 }H; 73 char s[N],tmps[N]; 74 int L; 75 void read(){ 76 int n;scanf("%d",&n); 77 scanf("%s",s); 78 L=strlen(s); 79 int le=strlen(s); s[le]='$';s[++le]='\0'; 80 for (int i=0;i<n;i++){ 81 scanf("%s",tmps); 82 int l=strlen(tmps); 83 strcpy(s+le,tmps); 84 le+=l; 85 s[le]='#'; s[++le]='\0'; 86 }s[le]='{';s[le+1]='\0'; 87 //cout<<s<<endl; 88 } 89 int lx[N]; 90 91 void solve(){ 92 int n=strlen(s); 93 int tmp=H.height[1]; 94 for (int i=0;i<L;i++) lx[i]=0; 95 for (int i=1;i<n-1;i++){ 96 if (H.SA[i]<L){ 97 lx[H.SA[i]]=tmp; 98 tmp=min(tmp,H.height[i+1]); 99 }else { 100 tmp=H.height[i+1]; 101 } 102 } 103 tmp=H.height[n-1]; 104 for (int i=n-2;i>0;i--){ 105 if (H.SA[i]<L){ 106 if (lx[H.SA[i]]<tmp) lx[H.SA[i]]=tmp; 107 tmp=min(tmp,H.height[i]); 108 }else { 109 tmp=H.height[i]; 110 } 111 } 112 LL ret=0; 113 114 for (int i=1;i<n;i++){ 115 if (H.SA[i]<L){ 116 ret+=L-H.SA[i]-lx[H.SA[i]]; 117 if (H.SA[i-1]<L){ 118 if (H.height[i]>lx[H.SA[i]]) ret-=H.height[i]-lx[H.SA[i]]; 119 } 120 } 121 } 122 printf("%I64d\n",ret); 123 } 124 int main(){ 125 int T,cas=0;scanf("%d",&T); 126 while (T--){ 127 read(); 128 H.build_sa(s); 129 printf("Case %d: ",++cas); 130 solve(); 131 } 132 return 0; 133 }