KMP & 扩展KMP & Manacher
A Number Sequence
求b序列在a序列出现的次数,KMP模板题:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <string.h> 3 #include <stdio.h> 4 char str[10010],str1[1000010]; 5 int nex[10010]; 6 void init(){ 7 int j = nex[0] = -1, i = 0; 8 int len = strlen(str); 9 while(i < len){ 10 if(j == -1 || str[i] == str[j]){ 11 nex[++i] = ++j; 12 }else j = nex[j]; 13 } 14 } 15 int KMP(){ 16 int i = 0, j = 0, sum = 0; 17 int len = strlen(str), len1 = strlen(str1); 18 while(j < len1){ 19 if(i == -1 || str[i] == str1[j]){ 20 i++;j++; 21 }else i = nex[i]; 22 if(i == len) sum++; 23 } 24 return sum; 25 } 26 using namespace std; 27 int main(){ 28 int n; 29 scanf("%d",&n); 30 while(n--){ 31 scanf("%s%s",str,str1); 32 init(); 33 /*for(int i = 0; i <= strlen(str); i ++){ 34 printf("%d ",nex[i]); 35 } 36 printf("\n");*/ 37 printf("%d\n",KMP()); 38 memset(str,0,sizeof(str)); 39 memset(str1,0,sizeof(str1)); 40 memset(nex,0,sizeof(nex)); 41 } 42 return 0; 43 }
B - Oulipo
求第一个字符串在第二个字符串中出现的次数,KMP模板题:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <string.h> 3 #include <stdio.h> 4 char str[10010],str1[1000010]; 5 int nex[10010]; 6 void init(){ 7 int j = nex[0] = -1, i = 0; 8 int len = strlen(str); 9 while(i < len){ 10 if(j == -1 || str[i] == str[j]){ 11 nex[++i] = ++j; 12 }else j = nex[j]; 13 } 14 } 15 int KMP(){ 16 int i = 0, j = 0, sum = 0; 17 int len = strlen(str), len1 = strlen(str1); 18 while(j < len1){ 19 if(i == -1 || str[i] == str1[j]){ 20 i++;j++; 21 }else i = nex[i]; 22 if(i == len) sum++; 23 } 24 return sum; 25 } 26 using namespace std; 27 int main(){ 28 int n; 29 scanf("%d",&n); 30 while(n--){ 31 scanf("%s%s",str,str1); 32 init(); 33 /*for(int i = 0; i <= strlen(str); i ++){ 34 printf("%d ",nex[i]); 35 } 36 printf("\n");*/ 37 printf("%d\n",KMP()); 38 memset(str,0,sizeof(str)); 39 memset(str1,0,sizeof(str1)); 40 memset(nex,0,sizeof(nex)); 41 } 42 return 0; 43 }
C - 剪花布条
求第二个字符串在第一个字符串中出现的次数,不能重复,KMP中每次找到让其下边重置为0就行了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 using namespace std; 5 char str[1010],str1[1010]; 6 int nex[1010]; 7 void init(){ 8 int j = nex[0] = -1, i = 0; 9 int len1 = strlen(str1); 10 while(i < len1){ 11 if(j == -1 || str1[i] == str1[j]){ 12 nex[++i] = ++j; 13 }else j = nex[j]; 14 } 15 } 16 int KMP(){ 17 int i = 0,j = 0, ans = 0; 18 int len = strlen(str), len1 = strlen(str1); 19 while(i < len){ 20 if(j == -1 || str[i] == str1[j]){ 21 i++;j++; 22 if(j == len1){ 23 ans++;j=0; 24 } 25 }else j = nex[j]; 26 } 27 return ans; 28 } 29 30 int main(){ 31 while(scanf("%s",str)!=EOF){ 32 if(!strcmp(str,"#"))break; 33 scanf("%s",str1); 34 init(); 35 printf("%d\n",KMP()); 36 memset(str,0,sizeof(str)); 37 memset(str1,0,sizeof(str1)); 38 } 39 return 0; 40 }
D - Cyclic Nacklace
这题就是求循环节。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 using namespace std; 5 char str[100010]; 6 int nex[100010]; 7 void init(){ 8 int j = nex[0] = -1, i = 0; 9 int len = strlen(str); 10 while(i < len){ 11 if(j == -1 || str[i] == str[j]){ 12 nex[++i] = ++j; 13 }else j = nex[j]; 14 } 15 } 16 int KMP(){ 17 int len = strlen(str); 18 int ans = len -nex[len]; 19 if(!nex[len])return len; 20 else if(len%ans) return ans-len%ans; 21 else return 0; 22 } 23 int main(){ 24 int t; 25 scanf("%d",&t); 26 while(t--){ 27 scanf("%s",str); 28 init(); 29 printf("%d\n",KMP()); 30 } 31 return 0; 32 }
E - Period
输出一遍next数组就看出规则了,直接过了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 using namespace std; 5 const int MAX = 1e6+10; 6 int n, nex[MAX]; 7 char str[MAX]; 8 void init(){ 9 int j = nex[0] = -1, i = 0; 10 int len = strlen(str); 11 while(i < len){ 12 if(j == -1 || str[i] == str[j]){ 13 nex[++i] = ++j; 14 }else j = nex[j]; 15 } 16 } 17 void KMP(){ 18 int len = strlen(str); 19 for(int i = 2; i <= len; i ++){ 20 int flag = 0, ans = i-nex[i]; 21 if(i%ans || ans == i)continue; 22 printf("%d %d\n",i,i/(i-nex[i])); 23 } 24 printf("\n"); 25 } 26 int main(){ 27 int k = 1; 28 while(scanf("%d",&n)!=EOF){ 29 if(!n)break; 30 scanf("%s",str); 31 printf("Test case #%d\n",k++); 32 init(); 33 /*for(int i = 0; i <= strlen(str); i ++){ 34 printf("%d ",nex[i]); 35 } 36 printf("\n");*/ 37 KMP(); 38 } 39 return 0; 40 }
F - Power Strings
关于循环节的问题。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 using namespace std; 5 const int MAX = 1e6+10; 6 char str[MAX]; 7 int nex[MAX]; 8 void init(){ 9 int j = nex[0] = -1, i = 0; 10 int len = strlen(str); 11 while(i < len){ 12 if(j == -1 || str[i] == str[j]){ 13 nex[++i] = ++j; 14 }else j = nex[j]; 15 } 16 } 17 int main(){ 18 while(scanf("%s",str)!=EOF){ 19 if(str[0] == '.')break; 20 init(); 21 int len = strlen(str); 22 int ans = len - nex[len]; 23 if(len%ans==0) 24 printf("%d\n",len/ans); 25 else printf("1\n"); 26 memset(str,0,sizeof(str)); 27 memset(nex,0,sizeof(nex)); 28 } 29 return 0; 30 }
G - Seek the Name, Seek the Fame
求循环的位置,用数组保存下输出就行了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 using namespace std; 5 char str[400010]; 6 int nex[400010]; 7 int a[400010]; 8 void init(){ 9 int j = nex[0] = -1, i = 0; 10 int len = strlen(str); 11 while(i < len){ 12 if(j == -1 || str[i] == str[j]) nex[++i] = ++j; 13 else j = nex[j]; 14 } 15 } 16 int main(){ 17 while(scanf("%s",str)!=EOF){ 18 init(); 19 int k = 0,len = strlen(str); 20 int i = len; 21 while(nex[i]){ 22 a[k++] = nex[i]; 23 i = nex[i]; 24 } 25 for(int i = k-1; i >= 0; i --){ 26 printf("%d ",a[i]); 27 } 28 printf("%d\n",len); 29 } 30 return 0; 31 }
H - Blue Jeans
直接暴力就可以做了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<string.h> 3 #include<iostream> 4 using namespace std; 5 6 int main(){ 7 int t,n,i,j; 8 string str[11]; 9 scanf("%d",&t); 10 while(t--){ 11 scanf("%d",&n); 12 for(i=0;i<n;i++) 13 cin>>str[i]; 14 string ans; 15 for(i=3;i<=60;i++){ 16 for(j=0;j<=60-3;j++){ 17 bool flag = true; 18 string s=str[0].substr(j,i); 19 for(int k = 1; k < n; k ++) 20 if(str[k].find(s) == string::npos){ 21 flag = false; 22 break; 23 } 24 if(flag && s.size() > ans.size()) 25 ans = s; 26 else if(flag && s.size() == ans.size() && s < ans) 27 ans = s; 28 } 29 } 30 if(!ans.empty()) 31 printf("%s\n",ans.c_str()); 32 else 33 printf("no significant commonalities\n"); 34 } 35 return 0; 36 }
I - Simpsons’ Hidden Talents
扩展KMP模板题。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 using namespace std; 5 char str1[50010],str2[50010]; 6 int nex[50010],extend[50010]; 7 8 void init(){ 9 int len = strlen(str1); 10 nex[0] = len; 11 int a, p; 12 for(int i = 1,j=-1; i < len; i++,j--){ 13 if(j < 0 || i+nex[i-a] >= p){ 14 if(j < 0) 15 p = i,j = 0; 16 while(p < len && str1[p] == str1[j]) 17 p++,j++; 18 nex[i] = j; 19 a = i; 20 }else nex[i] = nex[i-a]; 21 } 22 } 23 void getExtend(){ 24 int a,p; 25 int len1 = strlen(str1), len2 = strlen(str2); 26 for(int i = 0,j=-1; i < len2; i++,j--){ 27 if(j < 0 || i+nex[i-a]>=p){ 28 if(j<0) 29 p=i,j=0; 30 while(p<len2 && j<len1 && str2[p] == str1[j]) 31 p++,j++; 32 extend[i] = j; 33 a = i; 34 }else extend[i] = extend[i-a]; 35 } 36 } 37 int main(){ 38 while(scanf("%s%s",str1,str2)!=EOF){ 39 init(); 40 getExtend(); 41 int i, len2 = strlen(str2); 42 for(i = 0; i < len2; i ++){ 43 if(i+extend[i] == len2){ 44 printf("%s %d\n",str2+i,extend[i]); 45 break; 46 } 47 } 48 if(i == len2)printf("0\n"); 49 } 50 return 0; 51 }
J - Count the string (***)
主要是要理解以i结尾的子串中含前缀的数量加上前j个字符这一前缀。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 const int MAX = 200010,Mod = 10007; 5 char str[MAX]; 6 int nex[MAX],sum[MAX],ans; 7 void init(){ 8 int j = nex[0] = -1, i = 0; 9 int len = strlen(str); 10 while(i < len){ 11 if(j == -1 || str[i] == str[j]){ 12 if(j!=-1){ 13 sum[i] = sum[j]+1; 14 ans+=sum[i]; 15 } 16 nex[++i] = ++j; 17 } 18 else j = nex[j]; 19 } 20 } 21 int main(){ 22 int t,n; 23 scanf("%d",&t); 24 while(t--){ 25 scanf("%d%s",&n,str); 26 ans = 0; 27 init(); 28 printf("%d\n",(ans+n)%Mod); 29 memset(str,0,sizeof(str)); 30 memset(sum,0,sizeof(sum)); 31 } 32 return 0; 33 }
K - Clairewd’s message
这题理解好久才懂题意,就是第一行给你一个有26字符的字符串,分别对于a,b,c,,z,。第二行字符串中是密文加明文,密文要大于等于明文,明文可能也没有,要你输出密文加完整的明文,由于密文都有,求出明文就好办了。![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <map> 5 using namespace std; 6 const int MAX = 100010; 7 char str[MAX],s[30],str1[MAX]; 8 int nex[MAX],extend[MAX]; 9 map<char,char> mp; 10 void init(){ 11 int len = strlen(str1),a,p; 12 nex[0] = len; 13 for(int i = 1, j = -1; i < len; i ++, j--){ 14 if(j < 0 || i+nex[i-a] >= p){ 15 if(j < 0) 16 p=i,j=0; 17 while(p < len && str1[p]==str1[j]) 18 p++,j++; 19 nex[i] = j; 20 a = i; 21 }else nex[i] = nex[i-a]; 22 } 23 } 24 void KMP(){ 25 int a,p; 26 int len = strlen(str), len1 = strlen(str1); 27 for(int i = 1, j = -1; i < len; i++,j--){ 28 if(j<0 || i+nex[i-a] >= p){ 29 if(j < 0) 30 p=i,j=0; 31 while(p < len && str[p]==str1[j]) 32 p++,j++; 33 extend[i] = j; 34 a = i; 35 }else extend[i] = nex[i-a]; 36 } 37 } 38 int main(){ 39 int t; 40 scanf("%d",&t); 41 while(t--){ 42 scanf("%s%s",s,str); 43 for(int i = 0;i < 26; i ++) 44 mp[s[i]] = 'a'+i; 45 for(int i = 0; str[i]; i ++) 46 str1[i] = mp[str[i]]; 47 printf("%s",str,str1); 48 init(); 49 KMP(); 50 int k,len=strlen(str); 51 //printf("\n------%s---------\n",str1); 52 for(k = (len+1)/2; k < len; k++){ 53 if(k+extend[k] == len) 54 break; 55 } 56 //printf("\n+++++++++%d++++++\n",k); 57 for(int i =len-k ;i < k; i++){ 58 putchar(str1[i]); 59 } 60 printf("\n"); 61 } 62 return 0; 63 }
L - Substrings
求最大的公共子串,暴力可以解决。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <algorithm> 5 using namespace std; 6 7 int main(){ 8 int t,n,i,j,k; 9 scanf("%d",&t); 10 string str[110]; 11 while(t--){ 12 scanf("%d",&n); 13 for(i=0;i<n;i++) 14 cin>>str[i]; 15 int ans = 0; 16 for(i = str[0].size();i > 0; i--){ 17 for(j = 0; j <= str[0].size()-i; j++){ 18 string s = str[0].substr(j,i); 19 string ss = s; 20 reverse(s.begin(),s.end()); 21 for(k = 1; k < n; k ++) 22 if(str[k].find(s,0) == -1 && str[k].find(ss,0) == -1){ 23 break; 24 } 25 if(k == n && s.size() > ans) 26 ans = s.size(); 27 } 28 } 29 printf("%d\n",ans); 30 } 31 return 0; 32 }
M - Corporate Identity
和L题差不多,暴力。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <algorithm> 5 using namespace std; 6 7 int main(){ 8 int n; 9 string str[4002]; 10 while(scanf("%d",&n)&&n){ 11 int cnt = 220; 12 string s, ans; 13 for(int i = 0; i < n; i++){ 14 cin>>str[i]; 15 if(str[i].size() < cnt){ 16 cnt = str[i].size(); 17 s = str[i]; 18 } 19 } 20 for(int i = cnt; i > 0; i--){ 21 for(int j = 0; j <= cnt-i; j++){ 22 string ss = s.substr(j,i); 23 int k; 24 for(k = 0; k < n; k ++){ 25 if(str[k].find(ss,0) == -1) 26 break; 27 } 28 if(k == n && ss.size() > ans.size()) 29 ans = ss; 30 else if(k==n && ss.size() == ans.size() && ans > ss) 31 ans = ss; 32 } 33 } 34 if(!ans.empty()) 35 printf("%s\n",ans.c_str()); 36 else printf("IDENTITY LOST\n"); 37 } 38 return 0; 39 }
N - String Problem
求最小字典和最大字典,并求出他们的数量,用最小表示法可以快速求最先字典,同理也可以求最大字典。次数就是循环节了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 using namespace std; 5 const int MAX = 1000010; 6 char str[MAX]; 7 int nex[MAX]; 8 void init(){ 9 int j = nex[0] = -1, i = 0; 10 int len = strlen(str); 11 while(i < len){ 12 if(j == -1 || str[i] == str[j]) nex[++i] = ++j; 13 else j = nex[j]; 14 } 15 } 16 int minAndMax(bool flag){ 17 int i = 0, j = 1, k = 0; 18 int len = strlen(str); 19 while(i<len && j<len && k<len){ 20 int t = str[(j+k)%len]-str[(i+k)%len]; 21 if(t == 0) k++; 22 else { 23 if(flag){ 24 if(t>0)j+=k+1; 25 else i+=k+1; 26 }else{ 27 if(t>0)i+=k+1; 28 else j+=k+1; 29 } 30 if(i==j)j++; 31 k=0; 32 } 33 } 34 return min(j,i); 35 } 36 int main(){ 37 while(scanf("%s",str)!=EOF){ 38 init(); 39 int MIN = minAndMax(true); 40 int MAX = minAndMax(false); 41 int len = strlen(str); 42 int cnt = len-nex[len]; 43 int ans = len%cnt?1:len/cnt; 44 printf("%d %d %d %d\n",MIN+1,ans,MAX+1,ans); 45 memset(str,0,sizeof(str)); 46 } 47 return 0; 48 }
O - How many
最小表示法加set可以解决。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <algorithm> 5 #include <set> 6 using namespace std; 7 char str[110]; 8 set<string> ss; 9 int Min_index(char *ss){ 10 int i = 0,j = 1, k = 0; 11 int len = strlen(ss); 12 while(i<len && j<len && k<len){ 13 int t = ss[(j+k)%len]-ss[(i+k)%len]; 14 if(t == 0)k++; 15 else{ 16 if(t>0) j+=k+1; 17 else i+=k+1; 18 k=0; 19 } 20 if(i==j)j++; 21 } 22 return min(i,j); 23 } 24 int main(){ 25 int n; 26 while(scanf("%d",&n)!=EOF){ 27 string s,ans; 28 for(int i = 0; i < n; i ++){ 29 scanf("%s",str); 30 int k = Min_index(str); 31 ans = str; 32 s = ans.substr(k,ans.length()-k)+ans.substr(0,k); 33 ss.insert(s); 34 } 35 printf("%d\n",ss.size()); 36 ss.clear(); 37 } 38 return 0; 39 }
P - Period II
next数组的运用。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 const int MAX = 1000010; 5 char str[MAX]; 6 int nex[MAX],a[MAX]; 7 void init(){ 8 int len = strlen(str),a,p; 9 nex[0] = len; 10 for(int i = 1,j = -1; i < len; i ++,j--){ 11 if(j<0 || i+nex[i-a] >= p){ 12 if(j < 0) 13 p=i,j=0; 14 while(p<len && str[p]==str[j]) 15 p++,j++; 16 nex[i]=j; 17 a=i; 18 }else nex[i] = nex[i-a]; 19 } 20 } 21 int main(){ 22 int n; 23 while(scanf("%d",&n)!=EOF){ 24 for(int i = 1; i <= n; i ++){ 25 scanf("%s",str); 26 init(); 27 int k = 0,len = strlen(str); 28 for(int j = 1; j < len; j++){ 29 if(j+nex[j] == len) 30 a[k++] = j; 31 } 32 printf("Case #%d: %d\n",i,k+1); 33 for(int j = 0; j < k; j ++) 34 printf("%d ",a[j]); 35 printf("%d\n",len); 36 } 37 } 38 return 0; 39 }
R - Best Reward
将字符串分成两半,不是回文的价值为0,是回文的每个字符代表一个价值,求最大价值,Manacher 的运用(***)。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 using namespace std; 5 const int MAX = 500010; 6 int t,v[27],p[MAX*2],sum[MAX],per[MAX],pos[MAX]; 7 char str[MAX*2]; 8 9 void init(){ 10 int id = 0,len = strlen(str); 11 for(int i = len; i >= 0; i--){ 12 str[i+i+2] = str[i]; 13 str[i+i+1] = '#'; 14 } 15 str[0] = '*'; 16 for(int i = 2; i <2*len+1; i++){ 17 if(id+p[id] > i) p[i] = min(p[2*id-i],p[id]+id-i); 18 else p[i] = 1; 19 while(str[i-p[i]] == str[i+p[i]]) 20 ++p[i]; 21 if(id+p[id] < p[i]+i) id = i; 22 if(i-p[i] == 0)per[p[i]-1] = t+1; 23 if(i+p[i] == len*2+2)pos[p[i]-1] = t+1; 24 } 25 } 26 int main(){ 27 scanf("%d",&t); 28 while(t--){ 29 for(int i = 0; i < 26; i ++) scanf("%d",&v[i]); 30 scanf("%s",str); 31 int len = strlen(str); 32 for(int i = 0; i < len; i ++){ 33 sum[i+1] += sum[i]+v[str[i]-'a']; 34 } 35 init(); 36 int ans = -1; 37 for(int i = 1; i < len; i ++){ 38 int tmp = 0; 39 if(per[i] == t+1)tmp+=sum[i]; 40 if(pos[len-i] == t+1) tmp+=(sum[len]-sum[i]); 41 if(tmp > ans) ans=tmp; 42 } 43 printf("%d\n",ans); 44 memset(per,0,sizeof(per)); 45 memset(pos,0,sizeof(pos)); 46 memset(sum,0,sizeof(sum)); 47 } 48 return 0; 49 }
T - Palindrome
Manacher的模板题。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 using namespace std; 5 const int MAX = 1000010; 6 char str[MAX<<1]; 7 int p[MAX<<1]; 8 int solve(){ 9 int ans = 0, id = 0, len = strlen(str); 10 for(int i = len; i >= 0; i --){ 11 str[i+i+2] = str[i]; 12 str[i+i+1] = '#'; 13 } 14 str[0] = '*'; 15 for(int i = 2; i<2*len+1; i ++){ 16 if(p[id] + id > i) p[i] = min(p[2*id-i],p[id]+id-i); 17 else p[i] = 1; 18 while(str[i-p[i]] == str[i+p[i]])++p[i]; 19 if(p[id] + id < p[i]+i) id = i; 20 if(ans < p[i]) ans = p[i]; 21 } 22 return ans-1; 23 } 24 int main(){ 25 int k = 1; 26 while(scanf("%s",str)!=EOF){ 27 if(str[0] == 'E')break; 28 printf("Case %d: %d\n",k++,solve()); 29 memset(str,0,sizeof(str)); 30 memset(p,0,sizeof(p)); 31 getchar(); 32 } 33 return 0; 34 }
U - 吉哥系列故事――完美队形II
Manacher的运用,加了一个条件,从左到中间那个人,身高需保证不下降。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 using namespace std; 5 const int MAX = 100010; 6 int a[MAX*2],p[MAX*2],n; 7 8 int solve(){ 9 int ans = 0,id = 0; 10 for(int i = n; i >= 0; i --){ 11 a[i+i+2] = a[i]; 12 a[i+i+1] = -1; 13 } 14 a[0] = -2; 15 for(int i = 2; i < 2*n+1; i ++){ 16 if(p[id]+id>i)p[i] = min(p[2*id-i],p[id]+id-i); 17 else p[i] = 1; 18 while(a[i-p[i]] == a[i+p[i]] && a[i-p[i]] <= a[i-p[i]+2]) 19 ++p[i]; 20 if(p[id]+id < p[i]+i)id = i; 21 if(ans < p[i]) ans = p[i]; 22 } 23 return ans; 24 } 25 int main(){ 26 int t; 27 scanf("%d",&t); 28 while(t--){ 29 scanf("%d",&n); 30 for(int i = 0; i < n; i ++) scanf("%d",&a[i]); 31 printf("%d\n",solve()-1); 32 } 33 return 0; 34 }
V - Girls' research
求最长回文子串,并输出初末位置和字符串
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 using namespace std; 5 const int MAX = 200010; 6 char c,str[MAX<<1],gg; 7 int p[MAX<<1]; 8 9 void solve(){ 10 int ans = 0, cnt = 0,id = 0, len = strlen(str); 11 for(int i = len; i >= 0; i --){ 12 str[i+i+2] = str[i]; 13 str[i+i+1] = '#'; 14 } 15 str[0] = '*'; 16 for(int i = 2; i<2*len+1; i ++){ 17 if(p[id] + id > i) p[i] = min(p[2*id-i],p[id]+id-i); 18 else p[i] = 1; 19 while(str[i-p[i]] == str[i+p[i]])++p[i]; 20 if(p[id] + id < p[i]+i) id = i; 21 if(ans < p[i]) ans = p[i],cnt=i; 22 } 23 //printf("%d\n",p[cnt]); 24 if(ans < 3){ 25 printf("No solution!\n"); 26 return; 27 } 28 if(str[cnt] == '#'){ 29 printf("%d %d\n",(cnt-p[cnt])/2,(cnt+p[cnt]-4)/2); 30 for(int i = (cnt-p[cnt]+2); i <= (cnt+p[cnt]-2); i+=2){ 31 printf("%c",str[i]); 32 } 33 printf("\n"); 34 }else{ 35 printf("%d %d\n",(cnt-p[cnt])/2,(cnt+p[cnt]-4)/2); 36 for(int i = (cnt-p[cnt]+2); i <= (cnt+p[cnt]-2); i+=2){ 37 printf("%c",str[i]); 38 } 39 printf("\n"); 40 } 41 } 42 43 int main(){ 44 while(scanf("%c %s%c",&c,str,&gg)!=EOF){ 45 for(int i = 0; str[i]; i ++){ 46 str[i] = str[i]-c+'a'; 47 if(str[i] < 'a') str[i] +=26; 48 } 49 //cout << str << endl; 50 solve(); 51 memset(str,0,sizeof(str)); 52 } 53 return 0; 54 }
W - 最长回文
Manacher模板题:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 using namespace std; 5 const int MAX = 110010; 6 char str[MAX<<1]; 7 int p[MAX<<1]; 8 int solve(){ 9 int ans = 0, id = 0, len = strlen(str); 10 for(int i = len; i >= 0; i --){ 11 str[i+i+2] = str[i]; 12 str[i+i+1] = '#'; 13 } 14 str[0] = '*'; 15 for(int i = 2; i<2*len+1; i ++){ 16 if(p[id] + id > i) p[i] = min(p[2*id-i],p[id]+id-i); 17 else p[i] = 1; 18 while(str[i-p[i]] == str[i+p[i]])++p[i]; 19 if(p[id] + id < p[i]+i) id = i; 20 if(ans < p[i]) ans = p[i]; 21 } 22 return ans-1; 23 } 24 int main(){ 25 while(scanf("%s",str)!=EOF){ 26 printf("%d\n",solve()); 27 memset(str,0,sizeof(str)); 28 memset(p,0,sizeof(p)); 29 getchar(); 30 } 31 return 0; 32 }
X - Wow! Such Doge!
输入输出的处理。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 using namespace std; 5 int main(){ 6 char c; 7 int ans = 0,d = 0, o = 0, g = 0, e = 0; 8 while((c=getchar())!=EOF){ 9 if(c == ' ' || c == '\n'){ 10 d=o=g=e=0; 11 continue; 12 } 13 if(isalpha(c)) 14 c = tolower(c); 15 16 if(c == 'd'){ 17 d=1;o=g=e=0; 18 }else if(c == 'o' && o==0){ 19 if(d==1){ 20 o=1;g=e=0; 21 } 22 }else if(c == 'g' && g==0){ 23 if(d==1&& o==1){ 24 g=1;e=0; 25 } 26 }else if(c == 'e' && e==0){ 27 if(d==1&&o==1&&g==1){ 28 ans++; 29 d=o=g=e=0; 30 } 31 }else { 32 d=o=g=e=0; 33 } 34 } 35 printf("%d\n",ans); 36 return 0; 37 }
Y - Theme Section
求左边中间和右边最长的公共部分的长度
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 const int MAX = 1e6+10; 5 char str[MAX]; 6 int nex[MAX],a[MAX/3]; 7 void init(){ 8 int j = nex[0] = -1, i = 0; 9 int len = strlen(str); 10 while(i < len){ 11 if(j == -1 || str[i] == str[j]){ 12 nex[++i] = ++j; 13 }else j = nex[j]; 14 } 15 } 16 int KMP(){ 17 int len = strlen(str); 18 int j = nex[len],i = 0; 19 while(j != -1){ 20 if(j<=MAX/3) 21 a[i++] = j; 22 j = nex[j]; 23 } 24 if(i == 0 || a[0] == 0) return 0; 25 for(int k = 0; k < i; k ++){ 26 for(int l = a[k]+1; l <= len-a[k]; ++l){ 27 if(nex[l] == a[k]) 28 return a[k]; 29 } 30 } 31 } 32 int main(){ 33 int n; 34 scanf("%d",&n); 35 while(n--){ 36 scanf("%s",str); 37 init(); 38 printf("%d\n",KMP()); 39 memset(str,0,sizeof(str)); 40 } 41 return 0; 42 }