KMP · 扩展KMP · Manacher 专题

来源:互联网 发布:布达佩斯大饭店 知乎 编辑:程序博客网 时间:2024/06/02 03:30

涉及到的知识点:KMP,扩展KMP,Manacher算法,最小最大表示

牢记住:next[i]表示前i个字符所组成的字符串的最大前后缀匹配长度。

Number Sequence

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70325#problem/

判断一个字符串是否在另一个字符串中出现,如果出现,则输出最小的位置,否则输出-1.。

[cpp] view plain copy
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxn=1000010;  
  7. const int maxm=10010;  
  8. int a[maxn];//主串  
  9. int b[maxm];//模式串  
  10. int lena,lenb;  
  11. int nex[maxm];  
  12.   
  13. void kmp_pre()  
  14. {  
  15.     int i,j;  
  16.     j=nex[0]=-1;  
  17.     i=0;  
  18.     while(i<lenb)  
  19.     {  
  20.         while(j!=-1&&b[i]!=b[j])  
  21.             j=nex[j];  
  22.         nex[++i]=++j;  
  23.     }  
  24. }  
  25.   
  26. int KMP()  
  27. {  
  28.     int i,j;  
  29.     kmp_pre();  
  30.     i=j=0;  
  31.     while(i<lena)  
  32.     {  
  33.         while(j!=-1&&a[i]!=b[j])  
  34.             j=nex[j];  
  35.         i++;j++;  
  36.         if(j>=lenb)  
  37.             return i-lenb+1;  
  38.     }  
  39.     return -1;  
  40. }  
  41.   
  42. int main()  
  43. {  
  44.     int t;rd(t);  
  45.     while(t--)  
  46.     {  
  47.         rd2(lena,lenb);  
  48.         for(int i=0;i<lena;i++)  
  49.             rd(a[i]);  
  50.         for(int i=0;i<lenb;i++)  
  51.             rd(b[i]);  
  52.         printf("%d\n",KMP());  
  53.     }  
  54.     return 0;  
  55. }  

Oulipo

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70325#problem/B

问主串中含有多少个模式串,可重叠。

[cpp] view plain copy
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxn=1000010;  
  7. const int maxm=10010;  
  8. char a[maxn];//主串  
  9. char b[maxm];//模式串  
  10. int lena,lenb;  
  11. int nex[maxm];  
  12.   
  13. void kmp_pre()  
  14. {  
  15.     int i,j;  
  16.     j=nex[0]=-1;  
  17.     i=0;  
  18.     while(i<lenb)  
  19.     {  
  20.         while(j!=-1&&b[i]!=b[j])  
  21.             j=nex[j];  
  22.         nex[++i]=++j;  
  23.     }  
  24. }  
  25.   
  26. int KMP_count()  
  27. {  
  28.     int i,j;  
  29.     int ans=0;  
  30.     kmp_pre();  
  31.     i=j=0;  
  32.     while(i<lena)  
  33.     {  
  34.         while(j!=-1&&a[i]!=b[j])  
  35.             j=nex[j];  
  36.         i++,j++;  
  37.         if(j>=lenb)  
  38.         {  
  39.             ans++;  
  40.             j=nex[j];  
  41.         }  
  42.     }  
  43.     return ans;  
  44. }  
  45.   
  46. int main()  
  47. {  
  48.     int t;  
  49.     rd(t);  
  50.     while(t--)  
  51.     {  
  52.         scanf("%s",b);  
  53.         scanf("%s",a);  
  54.         lena=strlen(a);  
  55.         lenb=strlen(b);  
  56.         printf("%d\n",KMP_count());  
  57.     }  
  58.     return 0;  
  59. }  

剪花布条

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70325#problem/C

求主串中含有多少个模式串,不可重叠。

[cpp] view plain copy
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxn=1000010;  
  7. const int maxm=10010;  
  8. char a[maxn];//主串  
  9. char b[maxm];//模式串  
  10. int lena,lenb;  
  11. int nex[maxm];  
  12.   
  13. void kmp_pre()  
  14. {  
  15.     int i,j;  
  16.     j=nex[0]=-1;  
  17.     i=0;  
  18.     while(i<lenb)  
  19.     {  
  20.         while(j!=-1&&b[i]!=b[j])  
  21.             j=nex[j];  
  22.         nex[++i]=++j;  
  23.     }  
  24. }  
  25.   
  26. int KMP_count()  
  27. {  
  28.     int i,j;  
  29.     int ans=0;  
  30.     kmp_pre();  
  31.     i=j=0;  
  32.     while(i<lena)  
  33.     {  
  34.         while(j!=-1&&a[i]!=b[j])  
  35.             j=nex[j];  
  36.         i++,j++;  
  37.         if(j>=lenb)  
  38.         {  
  39.             ans++;  
  40.             j=0;  
  41.         }  
  42.     }  
  43.     return ans;  
  44. }  
  45.   
  46. int main()  
  47. {  
  48.     while(scanf("%s",a)&&a[0]!='#')  
  49.     {  
  50.         scanf("%s",b);  
  51.         lena=strlen(a);  
  52.         lenb=strlen(b);  
  53.         printf("%d\n",KMP_count());  
  54.     }  
  55.     return 0;  
  56. }  

Cyclic Nacklace

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70325#problem/D

给定一个字符串,问最少在尾部加多少个字符,使得该字符串可以分为相等的几份。比如aaa,加0个,因为aaa是由三份a组成的,再比如abcde,那么得加5个,即abcdeabcde,

可以分为相等的两份。

原来字符串设cir=len-next[len] 意思是最小循环节的长度,如果它不等于本身的长度且lenb%cir等于0的话,就不用再加任何字符了,否则,再添加cir-lenb%cir个字符,把末尾的部分凑成一个循环节。

[cpp] view plain copy
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxm=100010;  
  7. char b[maxm];//模式串  
  8. int lenb;  
  9. int nex[maxm];  
  10.   
  11. void kmp_pre()  
  12. {  
  13.     int i,j;  
  14.     j=nex[0]=-1;  
  15.     i=0;  
  16.     while(i<lenb)  
  17.     {  
  18.         while(j!=-1&&b[i]!=b[j])  
  19.             j=nex[j];  
  20.         nex[++i]=++j;  
  21.     }  
  22. }  
  23.   
  24. int main()  
  25. {  
  26.     int t;  
  27.     rd(t);  
  28.     while(t--)  
  29.     {  
  30.         scanf("%s",b);  
  31.         lenb=strlen(b);  
  32.         kmp_pre();  
  33.         int cir=lenb-nex[lenb];//最小循环节的长度  abbbab,循环节的长度为4,因为最后一个ab是循环节的前缀  
  34.         //abababab的cir值为2  
  35.         if(cir!=lenb&&lenb%cir==0)  
  36.             printf("0\n");  
  37.         else  
  38.             printf("%d\n",cir-lenb%cir);  
  39.     }  
  40.     return 0;  
  41. }  

Period

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70325#problem/E

给定一个长度为n的字符串,求它每个前缀的最短循环节,换句话说,对于每个i(2<=i<=n),求一个最大的整数K(如果K存在),使得S的前i个字符组成的前缀是某个字符串重复K次得到。输出存在K的i和对应的K。

最小循环节为i-next[i], 如果i%(i-next[i])==0且next[i]!=0的话,那么前i个字符组成的前缀一定存在循环节,循环节的个数为 i/(i-next[i])。

[cpp] view plain copy
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxn=1000010;  
  7. int lenb;  
  8. char b[maxn];  
  9. int nex[maxn];  
  10.   
  11. void kmp_pre()  
  12. {  
  13.     int i,j;  
  14.     j=nex[0]=-1;  
  15.     i=0;  
  16.     while(i<lenb)  
  17.     {  
  18.         while(j!=-1&&b[i]!=b[j])  
  19.             j=nex[j];  
  20.         nex[++i]=++j;  
  21.     }  
  22. }  
  23.   
  24. int main()  
  25. {  
  26.     int c=1;  
  27.     while(rd(lenb)!=EOF&&lenb)  
  28.     {  
  29.         scanf("%s",b);  
  30.         kmp_pre();  
  31.         printf("Test case #%d\n",c++);  
  32.         for(int i=2;i<=lenb;i++)  
  33.         {  
  34.             int cha=i-nex[i];  
  35.             if(nex[i]!=0&&i%cha==0)  
  36.                 printf("%d %d\n",i,i/cha);  
  37.         }  
  38.         printf("\n");  
  39.     }  
  40.     return 0;  
  41. }  

Power Strings

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70325#problem/G

给出一个字符串,某个子串链接n次产生的,求最大的n。也就是求最小的循环节
如 aabaabaabaab,输出3
如 aabaaba ,输出7

[cpp] view plain copy
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxn=1010010;  
  7. int lenb;  
  8. char b[maxn];  
  9. int nex[maxn];  
  10.   
  11. void kmp_pre()  
  12. {  
  13.     int i,j;  
  14.     j=nex[0]=-1;  
  15.     i=0;  
  16.     while(i<lenb)  
  17.     {  
  18.         while(j!=-1&&b[i]!=b[j])  
  19.             j=nex[j];  
  20.         nex[++i]=++j;  
  21.     }  
  22. }  
  23.   
  24. int main()  
  25. {  
  26.     while(scanf("%s",b)==1&&b[0]!='.')  
  27.     {  
  28.         lenb=strlen(b);  
  29.         kmp_pre();  
  30.         int k=lenb-nex[lenb];//最小循环节,aabaabc,k=7  
  31.         if(lenb%k==0)  
  32.             printf("%d\n",lenb/k);  
  33.         else  
  34.             printf("1\n");  
  35.     }  
  36.     return 0;  
  37. }  

Seek the Name, Seek the Fame

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70325#problem/H

给定一个字符串,有多少个前缀等于后缀,输出前缀的位置.
比如
ababcababababcabab 输出2 4 9 18
aaaaa   输出1 2 3 4 5
abaaba 输出 1 3 6
就是next[]的回溯。
以abaaba为例
位置i       0 1 2 3 4 5 6
第几个   1  2 3 4 5 6 7
字符        a b a a b a
next[i]     -1 0 0 1 1 2 3
长度为6 ,注意next[6]的值,它代表的意思是前6个字母的前缀和后缀最长公共序列的长度,也就是aba
长度为6的前缀肯定是符合题意的,前缀等于后缀了.
回溯next[6]=3,也就是第6个字母往前3个字母组成的后缀(aba)和前三个字母组成的前缀
aba是相等的。再回溯next[3]=1,也就是第三个字母往前1个字母(包括第三个字母,也就是
a),和前面1个字母组成的前缀是相等的。因为 aba aba相等,那么前面aba的后缀a也就是后面aba
的后缀。
next[1]=0,结束。

[cpp] view plain copy
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxn=400010;  
  7. int lenb;  
  8. char b[maxn];  
  9. int nex[maxn];  
  10.   
  11. void kmp_pre()  
  12. {  
  13.     int i,j;  
  14.     j=nex[0]=-1;  
  15.     i=0;  
  16.     while(i<lenb)  
  17.     {  
  18.         while(j!=-1&&b[i]!=b[j])  
  19.             j=nex[j];  
  20.         nex[++i]=++j;  
  21.     }  
  22. }  
  23. int ans[maxn];  
  24.   
  25.   
  26. int main()  
  27. {  
  28.     while(gets(b))  
  29.     {  
  30.         lenb=strlen(b);  
  31.         kmp_pre();  
  32.         int c=0;  
  33.         for(int i=lenb;i!=0;i=nex[i])  
  34.         {  
  35.             ans[c++]=i;  
  36.         }  
  37.         for(int i=c-1;i>=1;i--)  
  38.             cout<<ans[i]<<" ";  
  39.         cout<<ans[0]<<endl;  
  40.     }  
  41.     return 0;  
  42. }  

Simpsons’ Hidden Talents

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70325#problem/J

给定两个字符串s1,s2,求最长的字符串,使得该字符串是s1的前缀,是s2的后缀,输出该字符串,以及长度。

将两个字符串连接s1+s2,求next[]数组,然后从next[ (s1+s2).length() ]开始向前回溯,next[i]表示前i个字符所组成的字符串的最大前后缀匹配长度,注意回溯过程中长度p要小于等于s1的长度且小于等于s2的长度,要求最长,满足该条件,退出即可。

[cpp] view plain copy
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. string s1,s2;  
  7. int lenb;  
  8. const int maxn=50010*2;  
  9. int nex[maxn];  
  10. void kmp_pre(string b)  
  11. {  
  12.     int i,j;  
  13.     j=nex[0]=-1;  
  14.     i=0;  
  15.     while(i<lenb)  
  16.     {  
  17.         while(j!=-1&&b[i]!=b[j])  
  18.             j=nex[j];  
  19.         nex[++i]=++j;  
  20.     }  
  21. }  
  22.   
  23.   
  24. int main()  
  25. {  
  26.     while(cin>>s1>>s2)  
  27.     {  
  28.         string s=s1+s2;  
  29.         int len1=s1.length();  
  30.         int len2=s2.length();  
  31.         lenb=s.length();  
  32.         kmp_pre(s);  
  33.         int p=nex[lenb];//最长的前缀=后缀,就是等于整个串  
  34.         while(p>len1||p>len2) //为什么要大于len2  aaba  ab这组测试数据就能解释  
  35.             p=nex[p];  
  36.         if(p!=0)  
  37.         {  
  38.             for(int i=0;i<p;i++)  
  39.                 cout<<s1[i];  
  40.             cout<<" "<<p<<endl;  
  41.         }  
  42.         else  
  43.             cout<<0<<endl;  
  44.     }  
  45.     return 0;  
  46. }  
Count the string

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70325#problem/K

给定一个字符串,求所有的前缀在字符串中出现的次数和.
比如 abab
前缀a 出现2次
ab  出现2次
aba出现1次  abab出现1一次
dp[i]表示前i(i从1开始)个字符组成的字符串中,有多少个前缀是以第i个字符结尾的
比如前i个字符为aba,那么dp[i]=2,因为aba前缀中有 a 和aba是以a结尾的
next[i]表示前i个字符中前缀和后缀的最大匹配长度,比如前i个字符是abab那么next[4]=
那么 dp[i]=dp[next[i]]+1,为什么呢? 假如 ababab,dp[6]=dp[4]+1,前六个字符包括前4个字符,
dp[4]是前四个字符所有前缀中以第四个字符结尾的个数,第6个字符又等于第4个字符,所以再加上它
本身ababab,就是dp[6].

[cpp] view plain copy
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. int lenb;  
  7. const int maxn=200010;  
  8. char b[maxn];  
  9. int nex[maxn];  
  10. const int mod=10007;  
  11. int ans;  
  12. int dp[maxn];  
  13.   
  14. void kmp_pre()  
  15. {  
  16.     int i,j;  
  17.     j=nex[0]=-1;  
  18.     i=0;  
  19.     while(i<lenb)  
  20.     {  
  21.         while(j!=-1&&b[i]!=b[j])  
  22.             j=nex[j];  
  23.         nex[++i]=++j;  
  24.     }  
  25. }  
  26.   
  27. int main()  
  28. {  
  29.     int t;rd(t);  
  30.     while(t--)  
  31.     {  
  32.         rd(lenb);  
  33.         scanf("%s",b);  
  34.         kmp_pre();  
  35.         memset(dp,0,sizeof(dp));  
  36.         ans=0;  
  37.         for(int i=1;i<=lenb;i++)  
  38.         {  
  39.             dp[i]=dp[nex[i]]+1;  
  40.             if(dp[i]>=mod)  
  41.                 dp[i]%=mod;  
  42.             ans+=dp[i];  
  43.             if(ans>=mod)  
  44.                 ans%=mod;  
  45.         }  
  46.         printf("%d\n",ans);  
  47.   
  48.     }  
  49.     return 0;  
  50. }  

Clairewd’s message(这题参考的网上的....有些地方没明白)

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70325#problem/L

S主串,T模式串
定义母串S,和字串T,设S的长度为n,T的长度为m,求S的每一个后缀与T的最长公共前缀,
也就是说,设extend数组,extend[i]表示T与S[i,n-1]的最长公共前缀,要求出所有extend[i](0<=i<n)。
设辅助数组next[i]表示T[i,m-1]和T的最长公共前缀长度
如果有一个位置extend[i]=m,则表示T在S中出现,而且是在位置i出现,这就是标准的KMP问题,
所以说拓展kmp是对KMP算法的扩展,所以一般将它称为扩展KMP算法。
资料:http://blog.csdn.net/dyx404514/article/details/41831947
本题:
给定一个转换表,也就是明文对应的暗文
再给你一个串, 里面是暗文+明文,明文不一定完整,甚至没有
让你以最短的形式补全这个串,使得前半部分为暗文,后半部分为对应的明文
原来串:   暗文+明文(明文可能没有)
译码过去: 明文+暗文
要求补齐的明文最短,那么就是求原来串的所有后缀与后来串的最长公共前缀。
因为原来串中的明文越长,需要补全的明文就越短。

[cpp] view plain copy
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxn=100010;  
  7. int nex[maxn];  
  8. int extend[maxn];  
  9. char s[maxn];//主串  
  10. char t[maxn];//模式串  
  11. int lens,lent;  
  12.   
  13. void pre_kmp()  
  14. {  
  15.     nex[0]=lent;  
  16.     int j=0;  
  17.     while(j+1<lent&&t[j]==t[j+1])  
  18.         j++;  
  19.     nex[1]=j;  
  20.     int k=1;  
  21.     for(int i=2;i<lent;i++)  
  22.     {  
  23.         int p=nex[k]+k-1;  
  24.         int L=nex[i-k];  
  25.         if(i+L<p+1)  
  26.             nex[i]=L;  
  27.         else  
  28.         {  
  29.             j=max(0,p-i+1);  
  30.             while(i+j<lent&&t[i+j]==t[j])  
  31.                 j++;  
  32.             nex[i]=j;  
  33.             k=i;  
  34.         }  
  35.     }  
  36. }  
  37.   
  38. void EKMP()  
  39. {  
  40.     pre_kmp();  
  41.     int j=0;  
  42.     while(j<lens&&j<lent&&t[j]==s[j])  
  43.         j++;  
  44.     extend[0]=j;  
  45.     int k=0;  
  46.     for(int i=1;i<lens;i++)  
  47.     {  
  48.         int p=extend[k]+k-1;  
  49.         int L=nex[i-k];  
  50.         if(i+L<p+1) extend[i]=L;  
  51.         else  
  52.         {  
  53.             j=max(0,p-i+1);  
  54.             while(i+j<lens&&j<lent&&s[i+j]==t[j])  
  55.                 j++;  
  56.             extend[i]=j;  
  57.             k=i;  
  58.         }  
  59.     }  
  60. }  
  61.   
  62. char table[maxn];//转换表  
  63. map<char,char>mp;  
  64.   
  65. int main()  
  66. {  
  67.     int cas;rd(cas);  
  68.     while(cas--)  
  69.     {  
  70.         scanf("%s",table);  
  71.         scanf("%s",s);  
  72.         lens=strlen(s);  
  73.         for(int i=0;i<26;i++)  
  74.             mp[table[i]]='a'+i;  
  75.         for(int i=0;i<lens;i++)  
  76.             t[i]=mp[s[i]];  
  77.         lent=strlen(t);//别忘了  
  78.         s[lens]=0;  
  79.         EKMP();  
  80.         //以上部分把extend[i]数组求完了.  
  81.         //*******************  
  82.         int p;  
  83.         for(p=0;p<lens;p++)  
  84.         {  
  85.             if(p+extend[p]>=lens&&p>=extend[p])///暂时还没有想明白.....  
  86.                 break;  
  87.         }  
  88.         for(int i=0;i<p;i++)  
  89.             printf("%c",s[i]);  
  90.         for(int i=0;i<p;i++)  
  91.             printf("%c",mp[s[i]]);  
  92.         printf("\n");  
  93.     }  
  94.     return 0;  
  95. }  

Substrings

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70325#problem/M

给定n个字符串,求这n个字符串的最长公共子串,这个公共子串可以是正着的,也可以是反着的。

找到长度最小的字符串,然后枚举子串,再去其它串里查找就可以了。

[cpp] view plain copy
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxn=110;  
  7. int n;  
  8. string str[maxn];  
  9. int minp,p;  
  10.   
  11. int main()  
  12. {  
  13.     int t;  
  14.     rd(t);  
  15.     while(t--)  
  16.     {  
  17.         rd(n);  
  18.         minp=10000;  
  19.         for(int i=1;i<=n;i++)  
  20.         {  
  21.             cin>>str[i];  
  22.             int tp=str[i].length();  
  23.             if(minp>tp)  
  24.             {  
  25.                 minp=tp;  
  26.                 p=i;  
  27.             }  
  28.         }  
  29.         //枚举第p个串的子串  
  30.         bool ok;  
  31.         int ans=0;  
  32.         for(int i=0;i<minp;i++)//起点  
  33.         {  
  34.              for(int j=1;i+j<=minp;j++)//长度  
  35.              {  
  36.                  string s1=str[p].substr(i,j);  
  37.                  string s2=s1;  
  38.                  reverse(s2.begin(),s2.end());  
  39.                  //去所有串里面找  
  40.                  ok=1;  
  41.                 for(int k=1;k<=n;k++)  
  42.                 {  
  43.                     if(str[k].find(s1,0)==-1&&str[k].find(s2,0)==-1)//注意这个  
  44.                     {  
  45.                         ok=0;  
  46.                         break;  
  47.                     }  
  48.                 }  
  49.                 if(ok)  
  50.                 {  
  51.                     if(ans<j)  
  52.                         ans=j;  
  53.                 }  
  54.              }  
  55.         }  
  56.         printf("%d\n",ans);  
  57.     }  
  58.     return 0;  
  59. }  

Corporate Identity

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70325#problem/N

求n个字符串的最长公共子串。如果长度相等,则输出字典序最小的那个。

找出长度最小的字符串,然后枚举该串的子串,然后进行Kmp就可以了。

[cpp] view plain copy
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxn=210;  
  7. char str[4010][maxn];  
  8. int nex[maxn];  
  9.   
  10. void kmp_pre(char b[],int lenb)  
  11. {  
  12.     int i,j;  
  13.     j=nex[0]=-1;  
  14.     i=0;  
  15.     while(i<lenb)  
  16.     {  
  17.         while(j!=-1&&b[i]!=b[j])  
  18.             j=nex[j];  
  19.         nex[++i]=++j;  
  20.     }  
  21. }  
  22.   
  23. bool KMP(char a[],char b[],int lena,int lenb)  
  24. {  
  25.     int i,j;  
  26.     kmp_pre(b,lenb);  
  27.     i=j=0;  
  28.     while(i<lena)  
  29.     {  
  30.         while(j!=-1&&a[i]!=b[j])  
  31.             j=nex[j];  
  32.         i++;j++;  
  33.         if(j>=lenb)  
  34.             return true;  
  35.     }  
  36.     return false;  
  37. }  
  38. int n;  
  39. int minlen,minp;  
  40.   
  41. int main()  
  42. {  
  43.     while(rd(n)!=EOF&&n)  
  44.     {  
  45.         minlen=1000;  
  46.         for(int i=1;i<=n;i++)  
  47.         {  
  48.             scanf("%s",str[i]);  
  49.             int tplen=strlen(str[i]);  
  50.             if(minlen>tplen)  
  51.             {  
  52.                 minlen=tplen;  
  53.                 minp=i;  
  54.             }  
  55.         }  
  56.         char ans[210];  
  57.         ans[0]='\0';  
  58.         int maxlen=-1;  
  59.         for(int i=0;i<minlen;i++)//枚举起点  
  60.         {  
  61.             for(int j=i;j<minlen;j++)//枚举终点  
  62.             {  
  63.                 if(j-i+1<maxlen)  
  64.                     continue;  
  65.                 char tp[210];  
  66.                 int cnt=0;  
  67.                 for(int k=i;k<=j;k++)  
  68.                     tp[cnt++]=str[minp][k];  
  69.                 tp[cnt]='\0';  
  70.                 bool ok=1;  
  71.                 int lenb=j-i+1;  
  72.                 for(int k=1;k<=n;k++)  
  73.                 {  
  74.                     int lena=strlen(str[k]);  
  75.                     if(!KMP(str[k],tp,lena,lenb))  
  76.                     {  
  77.                         ok=0;  
  78.                         break;  
  79.                     }  
  80.                 }  
  81.                 if(ok)  
  82.                 {  
  83.                     maxlen=strlen(ans);  
  84.                     if(maxlen<lenb)  
  85.                         strcpy(ans,tp);  
  86.                     if(maxlen==lenb)  
  87.                     {  
  88.                         if(strcmp(tp,ans)<0)  
  89.                             strcpy(ans,tp);  
  90.                     }  
  91.                 }  
  92.             }  
  93.         }  
  94.         if(maxlen==-1)  
  95.             printf("IDENTITY LOST\n");  
  96.         else  
  97.         {  
  98.             for(int i=0;i<maxlen;i++)  
  99.                 printf("%c",ans[i]);  
  100.             cout<<endl;  
  101.         }  
  102.     }  
  103.     return 0;  
  104. }  

String Problem

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70325#problem/O

给定一个字符串比如ababab,编号为1,那么由它可以生成其它五个字符串,每次把头部的字母移到尾部。(循环同构)

ababab  1

bababa  2

ababab 3

bababa 4

ababab 5

bababa 6

求字典序最小的编号以及出现的次数,如果出现多次,输出编号最小的那个,比如字典序最小的为 ababab,一共出现了三次,编号分别为1 3 5,那么要求输出1 (最小编号)以及3(出现次数)。   还有字典序最大的编号以及出现的次数。

编号好求,用最小表示法,返回的就是最小表示法第一个字母的位置,次数就是循环节数。

字符串的最小最大表示法
http://blog.csdn.net/acm_cxlove/article/details/7909087
http://blog.csdn.net/cclsoft/article/details/5467743(这个很容易懂)
http://www.tuicool.com/articles/bmERbm

[cpp] view plain copy
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxn=1000010;  
  7. char b[maxn];  
  8. int nex[maxn];  
  9. int lenb;  
  10.   
  11. void kmp_pre()  
  12. {  
  13.     int i,j;  
  14.     j=nex[0]=-1;  
  15.     i=0;  
  16.     while(i<lenb)  
  17.     {  
  18.         while(-1!=j&&b[i]!=b[j])  
  19.             j=nex[j];  
  20.         nex[++i]=++j;  
  21.     }  
  22. }  
  23. //最小最大表示法,flag为true返回最小表示,否则返回最大表示  
  24. int min_max_exp(char b[],int lenb,bool flag)  
  25. {  
  26.     int i=0,j=1,k=0;  
  27.     while(i<lenb&&j<lenb&&k<lenb)  
  28.     {  
  29.         int t=b[(j+k)%lenb]-b[(i+k)%lenb];  
  30.         if(t==0)  
  31.             k++;  
  32.         else  
  33.         {  
  34.             if(flag)  
  35.             {  
  36.                 if(t>0) j+=k+1;  
  37.                 else  i+=k+1;  
  38.             }  
  39.             else  
  40.             {  
  41.                 if(t>0) i+=k+1;  
  42.                 else  j+=k+1;  
  43.             }  
  44.             if(i==j) j++;  
  45.             k=0;  
  46.         }  
  47.     }  
  48.     return min(i,j);  
  49. }  
  50.   
  51.   
  52. int main()  
  53. {  
  54.     while(gets(b))  
  55.     {  
  56.         lenb=strlen(b);  
  57.         kmp_pre();  
  58.         int minp=min_max_exp(b,lenb,1);  
  59.         int maxp=min_max_exp(b,lenb,0);  
  60.         int cir=lenb-nex[lenb];  
  61.         int ans=lenb%cir?1:lenb/cir;  
  62.         printf("%d %d %d %d\n",minp+1,ans,maxp+1,ans);  
  63.     }  
  64.     return 0;  
  65. }  

How many

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70325#problem/P

给出n条长度相等的项链,用0 1表示,一条项链如果通过旋转和另外一条一样,
那么这两条就是同一种类。
问给出的这n条项链中有多少种类。
比如
4
0110
1100
1001
0011

0110 1100 1001 都可以旋转得到 0011
旋转也就是每次把第一个字母移到末尾就行了。
对n个字符串变换成最小表示法,然后就找有多少个不同的字符串就可以了。

[cpp] view plain copy
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxn=10010;  
  7.   
  8. int min_max_exp(char b[],int lenb,bool flag)  
  9. {  
  10.     int i=0,j=1,k=0;  
  11.     while(i<lenb&&j<lenb&&k<lenb)  
  12.     {  
  13.         int t=b[(j+k)%lenb]-b[(i+k)%lenb];  
  14.         if(t==0)  
  15.             k++;  
  16.         else  
  17.         {  
  18.             if(flag)  
  19.             {  
  20.                 if(t>0) j+=k+1;  
  21.                 else  i+=k+1;  
  22.             }  
  23.             else  
  24.             {  
  25.                 if(t>0) i+=k+1;  
  26.                 else  j+=k+1;  
  27.             }  
  28.             if(i==j) j++;  
  29.             k=0;  
  30.         }  
  31.     }  
  32.     return min(i,j);  
  33. }  
  34. int n;  
  35. map<string,int>mp;  
  36. char str[maxn][110];  
  37.   
  38. int main()  
  39. {  
  40.     while(rd(n)!=EOF)  
  41.     {  
  42.         mp.clear();  
  43.         for(int i=1;i<=n;i++)  
  44.         {  
  45.             scanf("%s",str[i]);  
  46.             int lenb=strlen(str[i]);  
  47.             int p=min_max_exp(str[i],lenb,1);  
  48.             string tp="";  
  49.             //cout<<"pppp "<<p<<endl;  
  50.             for(int k=0;k<lenb;k++)  
  51.             {  
  52.                 int id=(p+k)%lenb;  
  53.                 tp.push_back(str[i][id]);  
  54.             }  
  55.            // cout<<"oooo   "<<tp<<endl;  
  56.             mp[tp]++;  
  57.         }  
  58.         printf("%d\n",mp.size());  
  59.     }  
  60.     return 0;  
  61. }  

Best Reward

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70325#problem/S

给定26个小写字母的价值,再给定一个由26个字母组成的字符串。
把该字符串切成两部分,如果该部分是回文串,那么该串的价值为每个字母的价值和,
否则该串的价值是0,问切成的这两部分的最大价值是多少。

用扩展KMP,枚举主串的位置,分别判断前i个字母组成的第一部分串是不是回文串,再判断
剩下的一部分串是不是回文串,取最大价值。
主串s,模式串t,extend[]数组是相对于主串的,意思extend[i]意思是主串从第i个位置到末尾组成的
串与模式串整个串的最长公共前缀。
模式串t,长度为lent,next[i]表示 t[i....lent-1]的串与t[0.....lent-1]的最长公共前缀。
主串s,长度为lens,extend[i]表示s[i.....lens-1]的串与t[0.....lent-1]的最长公共前缀。
该题进行两次KMP扩展。
判断主串的前i个字母是不是回文串,用主串作模式串,反转串做主串,进行KMP扩展,就可以判断了.
判断主串剩下的字母是不是回文串,用主串还是做主串,反转串做模式串,进行KMP扩展,就可以判断了。


[cpp] view plain copy
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxn=500010;  
  7. int nex[maxn];  
  8. int extend1[maxn];  
  9. int extend2[maxn];  
  10. char s[maxn];//主串  
  11. char t[maxn];//模式串  
  12. int lens,lent;  
  13.   
  14. void pre_kmp(char t[],int lent)//模式串  
  15. {  
  16.     nex[0]=lent;  
  17.     int j=0;  
  18.     while(j+1<lent&&t[j]==t[j+1])  
  19.         j++;  
  20.     nex[1]=j;  
  21.     int k=1;  
  22.     for(int i=2;i<lent;i++)  
  23.     {  
  24.         int p=nex[k]+k-1;  
  25.         int L=nex[i-k];  
  26.         if(i+L<p+1)  
  27.             nex[i]=L;  
  28.         else  
  29.         {  
  30.             j=max(0,p-i+1);  
  31.             while(i+j<lent&&t[i+j]==t[j])  
  32.                 j++;  
  33.             nex[i]=j;  
  34.             k=i;  
  35.         }  
  36.     }  
  37. }  
  38.   
  39. void EKMP(char s[],char t[],int lens,int lent,int extend[])//主串s,模式串t  
  40. {  
  41.     pre_kmp(t,lent);  
  42.     int j=0;  
  43.     while(j<lens&&j<lent&&t[j]==s[j])  
  44.         j++;  
  45.     extend[0]=j;  
  46.     int k=0;  
  47.     for(int i=1;i<lens;i++)  
  48.     {  
  49.         int p=extend[k]+k-1;  
  50.         int L=nex[i-k];  
  51.         if(i+L<p+1) extend[i]=L;  
  52.         else  
  53.         {  
  54.             j=max(0,p-i+1);  
  55.             while(i+j<lens&&j<lent&&s[i+j]==t[j])  
  56.                 j++;  
  57.             extend[i]=j;  
  58.             k=i;  
  59.         }  
  60.     }  
  61. }  
  62.   
  63. int val[26];  
  64. int sum[maxn];//疏忽了,第一次开的27,应该开字符串长度,意思是前i个字符的价值和  
  65. int n;  
  66.   
  67. int main()  
  68. {  
  69.     rd(n);  
  70.     while(n--)  
  71.     {  
  72.         sum[0]=0;  
  73.         for(int i=0;i<26;i++)  
  74.         {  
  75.             rd(val[i]);  
  76.         }  
  77.         scanf("%s",s);  
  78.         lens=lent=strlen(s);  
  79.         for(int i=1;i<=lens;i++)  
  80.         {  
  81.             sum[i]=sum[i-1]+val[s[i-1]-'a'];  
  82.         }  
  83.         for(int i=0;i<lens;i++)  
  84.         {  
  85.             t[i]=s[lens-i-1];  
  86.         }  
  87.         //第一次匹配把原串s,作为模式串,得到extend1数组  
  88.         //意思是原串的前i个字母是回文串  
  89.         EKMP(t,s,lent,lens,extend1);  
  90.         //第二次反过来  
  91.         EKMP(s,t,lens,lent,extend2);  
  92.         int ans=0;//要用0  
  93.         for(int i=1;i<lens;i++)  
  94.         {  
  95.             int tp=0;  
  96.             if(extend1[lens-i]==i)//原串的前i个是回文串  
  97.                 tp+=sum[i];  
  98.             if(extend2[i]==lens-i)  
  99.                 tp+=sum[lens]-sum[i];//原串的后len-i个是回文串  
  100.             if(ans<tp)  
  101.                 ans=tp;  
  102.         }  
  103.         printf("%d\n",ans);  
  104.     }  
  105.     return 0;  
  106. }  

Palindrome

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70325#problem/U

裸的最长回文子串,manacher算法解决

[cpp] view plain copy
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxn=1000010;  
  7. char MA[maxn<<1];  
  8. int MP[maxn<<1];  
  9. void Manacher(char s[],int len)  
  10. {  
  11.     int l=0;  
  12.     MA[l++]='$';  
  13.     MA[l++]='#';  
  14.     for(int i=0;i<len;i++)  
  15.     {  
  16.         MA[l++]=s[i];  
  17.         MA[l++]='#';  
  18.     }  
  19.     MA[l]=0;  
  20.     int mx=0,id=0;  
  21.     for(int i=0;i<l;i++)  
  22.     {  
  23.         MP[i]=mx>i?min(MP[2*id-i],mx-i):1;  
  24.         while(MA[i+MP[i]]==MA[i-MP[i]])  
  25.             MP[i]++;  
  26.         if(i+MP[i]>mx)  
  27.         {  
  28.             mx=i+MP[i];  
  29.             id=i;  
  30.         }  
  31.     }  
  32. }  
  33. char s[maxn];  
  34.   
  35. int main()  
  36. {  
  37.     int c=1;  
  38.     while(scanf("%s",s)==1)  
  39.     {  
  40.         if(s[0]=='E')  
  41.             break;  
  42.         int len=strlen(s);  
  43.         Manacher(s,len);  
  44.         int ans=0;  
  45.         for(int i=0;i<2*len+2;i++)  
  46.             ans=max(ans,MP[i]-1);  
  47.         printf("Case %d: %d\n",c++,ans);  
  48.     }  
  49.     return 0;  
  50. }  

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

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70325#problem/V

要求最长的回文串,条件为左边的数到中间不递减,中间的数到右边不递增。manacher算法

[cpp] view plain copy
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxn=100010;  
  7. int ma[maxn<<1];  
  8. int mp[maxn<<1];  
  9.   
  10. void manacher(int s[],int len)//对s数组进行manacher,该长度为len  
  11. {  
  12.     int l=0;  
  13.     ma[l++]=0;  
  14.     ma[l++]=-1;  
  15.     for(int i=0;i<len;i++)  
  16.     {  
  17.         ma[l++]=s[i];  
  18.         ma[l++]=-1;  
  19.     }  
  20.     ma[l]=-1;  
  21.     int mx=0,id=0;  
  22.     for(int i=0;i<l;i++)  
  23.     {  
  24.         mp[i]=mx>i?min(mp[2*id-i],mx-i):1;  
  25.         while(ma[i+mp[i]]==ma[i-mp[i]]&&ma[i-mp[i]]<=ma[i-mp[i]+2])//注意这个条件,保证不递减  
  26.             mp[i]++;  
  27.         if(i+mp[i]>mx)  
  28.         {  
  29.             mx=i+mp[i];  
  30.             id=i;  
  31.         }  
  32.     }  
  33. }  
  34. int n;  
  35. int s[maxn];  
  36. int main()  
  37. {  
  38.     int t;rd(t);  
  39.     while(t--)  
  40.     {  
  41.         rd(n);  
  42.         for(int i=0;i<n;i++)  
  43.             rd(s[i]);  
  44.         manacher(s,n);  
  45.         int ans=0;  
  46.         for(int i=0;i<2*n+2;i++)  
  47.             ans=max(ans,mp[i]-1);  
  48.         printf("%d\n",ans);  
  49.     }  
  50.     return 0;  
  51. }  

Girls' research

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70325#problem/W

首先给定一个字母ch,那么这个字母就是真正的a, 如果ch=b, 那么 b=a, c=b,d=c..........z=y, a=z....  如果 ch=c,那么 c=a,d=b,e=c,.....    ,z=x,a=y,b=z,也就是一个变换规则。

然后给定一个字符串,求该字符串的最长回文子串,输出该回文子串在原字符串中的左边界和右边界,以及按照变换规则把这部分回文子串输出。

比如样例 b    babd  (注意格式,中间有一个空格) ,    变换规则,  b->a  c->b,d->c.....a->z

babd的最长回文子串是bab,左边界位置为0,右边界位置为2,按照变换规则输出该回文串为aza.

如果最长回文子串的长度为1,输出No solution!

对原串用Manacher算法求最长回文子串,并记录位置。注意输入格式

[cpp] view plain copy
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxn=200010;  
  7. char ma[maxn<<1];  
  8. int mp[maxn<<1];  
  9. char str[maxn<<1];  
  10. map<int,char>change;//字母的变化保存  
  11. int ans;//最长回文子串的长度  
  12. int p;//最长回文子串中间的位置  
  13.   
  14. void manacher(int len)  
  15. {  
  16.     ans=-1;  
  17.     int l=0;  
  18.     ma[l++]='$';  
  19.     ma[l++]='#';  
  20.     for(int i=0;i<len;i++)  
  21.     {  
  22.         ma[l++]=str[i];  
  23.         ma[l++]='#';  
  24.     }  
  25.     ma[l]=0;  
  26.     int mx=0,id=0;  
  27.     for(int i=0;i<l;i++)  
  28.     {  
  29.         mp[i]=mx>i?min(mp[2*id-i],mx-i):1;  
  30.         while(ma[i+mp[i]]==ma[i-mp[i]])  
  31.             mp[i]++;  
  32.         if(i+mp[i]>mx)  
  33.         {  
  34.             mx=i+mp[i];  
  35.             id=i;  
  36.         }  
  37.         if(ans<mp[i]-1)  
  38.         {  
  39.             ans=mp[i]-1;  
  40.             p=i;  
  41.         }  
  42.     }  
  43. }  
  44.   
  45.   
  46. int main()  
  47. {  
  48.     char c;  
  49.     while(scanf("%c %s",&c,str)!=EOF)//注意输入格式,否则超时。。  
  50.     {  
  51.         getchar();  
  52.         int cha=c-'a';  
  53.         for(int i=0;i<26;i++)  
  54.             change[i]=((i+26-cha)%26+'a');  
  55.         //cout<<c[0]<<"    "<<str<<endl;  
  56.         //for(int i=0;i<26;i++)  
  57.          //   cout<<change[i]<<endl;  
  58.         int len=strlen(str);  
  59.         manacher(len);  
  60.         if(ans<2)  
  61.         {  
  62.             printf("No solution!\n");  
  63.             continue;  
  64.         }  
  65.         int L=p-ans+1;//ma[]数组中对应的最长回文的左边界  
  66.         int l=L/2-1;//最长回文子串对应到原数组中的左边界位置  
  67.         int r=l+ans-1;//最长回文对应到原数组中的右边界位置  
  68.         printf("%d %d\n",l,r);  
  69.         for(int k=l;k<=r;k++)  
  70.             printf("%c",change[str[k]-'a']);  
  71.         printf("\n");  
  72.     }  
  73.     return 0;  
  74. }  

最长回文

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70325#problem/X

学习manacher算法,复杂度O(n)

资料:http://blog.csdn.net/dyx404514/article/details/42061017

[cpp] view plain copy
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxn=110010;  
  7. char MA[maxn<<1];  
  8. int MP[maxn<<1];  
  9. void Manacher(char s[],int len)  
  10. {  
  11.     int l=0;  
  12.     MA[l++]='$';//防止越界  
  13.     MA[l++]='#';  
  14.     for(int i=0;i<len;i++)  
  15.     {  
  16.         MA[l++]=s[i];  
  17.         MA[l++]='#';  
  18.     }  
  19.     MA[l]=0;  
  20.     int mx=0,id=0;  
  21.     for(int i=0;i<l;i++)  
  22.     {  
  23.         MP[i]=mx>i?min(MP[2*id-i],mx-i):1;//2*id-i是关于id的对称点  
  24.         while(MA[i+MP[i]]==MA[i-MP[i]])  
  25.             MP[i]++;  
  26.         if(i+MP[i]>mx)  
  27.         {  
  28.             mx=i+MP[i];  
  29.             id=i;  
  30.         }  
  31.     }  
  32. }  
  33. char s[maxn];  
  34.   
  35. int main()  
  36. {  
  37.     while(scanf("%s",s)==1)  
  38.     {  
  39.         int len=strlen(s);  
  40.         Manacher(s,len);  
  41.         int ans=0;  
  42.         for(int i=0;i<2*len+2;i++)  
  43.             ans=max(ans,MP[i]-1);  
  44.         printf("%d\n",ans);  
  45.     }  
  46.     return 0;  
  47. }  
Wow! Such Doge!

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70325#problem/Y

求给定的文本中有多少个"doge",大小写不区分,先把所有大写字母转为小写字母,然后扫描一遍就可以了。注意输入格式。

输入:

adoge
cutedo 
yourge 
blownDoge
lovelyDooge
Wow! Such Dooooooooooooooge!!!
D0ge
dOge DOGE 
dogedoge

输出:

6

[cpp] view plain copy
  1. #define rd(x) scanf("%d",&x)  
  2. #define rd2(x,y)  scanf("%d%d",&x,&y)  
  3. #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)  
  4. using namespace std;  
  5. typedef long long ll;  
  6. const int maxn=10010;  
  7. char str[100010];  
  8.   
  9. int main()  
  10. {  
  11.     int cnt=0;  
  12.     while(gets(str))  
  13.     {  
  14.         int len=strlen(str);  
  15.         for(int i=0;i<len;i++)  
  16.             if(isalpha(str[i]))  
  17.             str[i]=tolower(str[i]);  
  18.         for(int i=0;i<len;i++)  
  19.         {  
  20.            // cout<<"i"<<i<<endl;  
  21.             if(i+3<len)  
  22.             {  
  23.                 if(str[i]=='d'&&str[i+1]=='o'&&str[i+2]=='g'&&str[i+3]=='e')  
  24.                 {  
  25.                     cnt++;  
  26.                    // cout<<"oo"<<cnt<<endl;  
  27.                     i+=3;  
  28.   
  29.                 }  
  30.             }  
  31.         }  
  32.     }  
  33.     printf("%d\n",cnt);  
  34.     return 0;  
  35. }  
阅读全文
0 0
原创粉丝点击