zoukankan      html  css  js  c++  java
  • 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("
    ");*/
    37         printf("%d
    ",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("
    ");*/
    37         printf("%d
    ",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
    ",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
    ",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
    ",i,i/(i-nex[i]));
    23     }
    24     printf("
    ");
    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
    ",k++);
    32         init();
    33         /*for(int i = 0; i <= strlen(str); i ++){
    34             printf("%d ",nex[i]);
    35         }
    36         printf("
    ");*/
    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
    ",len/ans);
    25         else printf("1
    ");
    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
    ",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
    ",ans.c_str());
    32         else 
    33             printf("no significant commonalities
    ");
    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
    ",str2+i,extend[i]);
    45                 break;
    46             }
    47         }
    48         if(i == len2)printf("0
    ");
    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
    ",(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("
    ------%s---------
    ",str1);
    52         for(k = (len+1)/2; k < len; k++){
    53             if(k+extend[k] == len)
    54                 break;
    55         }
    56         //printf("
    +++++++++%d++++++
    ",k);
    57         for(int i =len-k ;i < k; i++){
    58             putchar(str1[i]);
    59         }
    60         printf("
    ");
    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
    ",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
    ",ans.c_str());
    36         else printf("IDENTITY LOST
    ");
    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
    ",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
    ",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
    ",i,k+1);
    33             for(int j = 0; j < k; j ++)
    34                 printf("%d ",a[j]);
    35             printf("%d
    ",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
    ",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
    ",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
    ",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
    ",p[cnt]);
    24     if(ans < 3){
    25         printf("No solution!
    ");
    26         return;
    27     }
    28     if(str[cnt] == '#'){
    29          printf("%d %d
    ",(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("
    ");
    34     }else{
    35         printf("%d %d
    ",(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("
    ");
    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
    ",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 == '
    '){
    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
    ",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
    ",KMP());
    39         memset(str,0,sizeof(str));
    40     }
    41     return 0;
    42 }
    View Code
  • 相关阅读:
    BigPipe_高性能流水线页面技术
    高并发大流量网站 10 个解决方法
    崇高不是比惨
    utf-8无bom格式编码
    go.php
    微信+QQ跳转
    java 设计模式-单例
    HTML连载88-今天把努比亚界面仿真写完了(完结连载)
    Android连载10-动态添加页面、创建一个新闻app
    JavaScript连载9-三目运算符、综合复习
  • 原文地址:https://www.cnblogs.com/xingkongyihao/p/7147726.html
Copyright © 2011-2022 走看看