KMP & 扩展KMP & Manacher

A Number Sequence

求b序列在a序列出现的次数,KMP模板题:

 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 }
View Code

 

B - Oulipo

求第一个字符串在第二个字符串中出现的次数,KMP模板题:

 

 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 }
View Code

 

 

 

C - 剪花布条

求第二个字符串在第一个字符串中出现的次数,不能重复,KMP中每次找到让其下边重置为0就行了。

 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 }
View Code

 

D - Cyclic Nacklace

这题就是求循环节。

 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 }
View Code

 

E - Period

输出一遍next数组就看出规则了,直接过了。

 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 }
View Code

 

F - Power Strings

关于循环节的问题。

 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 }
View Code

 

G - Seek the Name, Seek the Fame

求循环的位置,用数组保存下输出就行了。

 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 }
View Code

 

H - Blue Jeans

直接暴力就可以做了。

 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 }
View Code

 

I - Simpsons’ Hidden Talents

扩展KMP模板题。

 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 }
View Code

 

J - Count the string   (***)

主要是要理解以i结尾的子串中含前缀的数量加上前j个字符这一前缀。

 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 }
View Code

 

 

K - Clairewd’s message

这题理解好久才懂题意,就是第一行给你一个有26字符的字符串,分别对于a,b,c,,z,。第二行字符串中是密文加明文,密文要大于等于明文,明文可能也没有,要你输出密文加完整的明文,由于密文都有,求出明文就好办了。
 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 }
View Code

 

 

L - Substrings

求最大的公共子串,暴力可以解决。

 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 }
View Code

 

M - Corporate Identity

和L题差不多,暴力。

 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 }
View Code

 

N - String Problem

求最小字典和最大字典,并求出他们的数量,用最小表示法可以快速求最先字典,同理也可以求最大字典。次数就是循环节了。

 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 }
View Code

 

O - How many

最小表示法加set可以解决。

 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 }
View Code

 

P - Period II

next数组的运用。

 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 }
View Code

 

R - Best Reward

将字符串分成两半,不是回文的价值为0,是回文的每个字符代表一个价值,求最大价值,Manacher 的运用(***)。

 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 }
View Code

 

T - Palindrome

Manacher的模板题。

 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 }
View Code

 

U - 吉哥系列故事――完美队形II

Manacher的运用,加了一个条件,从左到中间那个人,身高需保证不下降。

 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 }
View Code

 

V - Girls' research

求最长回文子串,并输出初末位置和字符串

 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 }
View Code

 

W - 最长回文

Manacher模板题:

 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 }
View Code

 

X - Wow! Such Doge!

输入输出的处理。

 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 }
View Code

 

Y - Theme Section

求左边中间和右边最长的公共部分的长度

 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 }
View Code

 

 

posted @ 2017-07-10 21:12  starry_sky  阅读(268)  评论(0编辑  收藏  举报