KMP算法:

kmp示例代码:

  1. void cal_next(char *str, int *next, int len)
  2. {
  3. next[0] = -1;//next[0]初始化为-1,-1表示不存在相同的最大前缀和最大后缀
  4. int k = -1;//k初始化为-1
  5. for (int q = 1; q <= len-1; q++)
  6. {
  7. while (k > -1 && str[k + 1] != str[q])//如果下一个不同,那么k就变成next[k],注意next[k]是小于k的,无论k取任何值。
  8. {
  9. k = next[k];//往前回溯
  10. }
  11. if (str[k + 1] == str[q])//如果相同,k++
  12. {
  13. k = k + 1;
  14. }
  15. next[q] = k;//这个是把算的k的值(就是相同的最大前缀和最大后缀长)赋给next[q]
  16. }
  17. }
  18. int KMP(char *str, int slen, char *ptr, int plen)
  19. {
  20. int *next = new int[plen];
  21. cal_next(ptr, next, plen);//计算next数组
  22. int k = -1;
  23. for (int i = 0; i < slen; i++)
  24. {
  25. while (k >-1&& ptr[k + 1] != str[i])//ptr和str不匹配,且k>-1(表示ptr和str有部分匹配)
  26. k = next[k];//往前回溯
  27. if (ptr[k + 1] == str[i])
  28. k = k + 1;
  29. if (k == plen-1)//说明k移动到ptr的最末端
  30. {
  31. //cout << "在位置" << i-plen+1<< endl;
  32. //k = -1;//重新初始化,寻找下一个
  33. //i = i - plen + 1;//i定位到该位置,外层for循环i++可以继续找下一个(这里默认存在两个匹配字符串可以部分重叠),感谢评论中同学指出错误。
  34. return i-plen+1;//返回相应的位置
  35. }
  36. }
  37. return -1;
  38. }
  39. char *str = "bacbababadababacambabacaddababacasdsd";
  40. char *ptr = "ababaca";
  41. int a = KMP(str, 36, ptr, 7);
  42. return 0;

kmp算法是用来找模式串是否在主串中出现,并返回第一次出现的位置。(模式串一般都比主串长度短,求的是模式串在主串中是否出现)

它有一个数组next[len](len是ptr字符串的长度),next[i]这里面放的是模式串的前i个字符的最长公共前后缀。(前缀不包括第i个字符)

时间复杂度:O(n+m)

算法过程:

你求的是模式串在主串中出现的位置,next[i]数组是模式串前i个字符的最长公共前后缀。
S1=abadfgag 
S2=abac
next[0]=-1
next[1]=-1
next[2]=1
next[3]=-1
第一次匹配从S1第0位开始,得到S1[0,2]==S2[0,2]
那么下一次匹配还要从S1第1位开始吗?
不需要。kmp优化的就是这里,因为next[2]=1
那么就有S2[0]=S2[2],又因为S1[0,2]==S2[0,2]
所以S1[0]==S1[2],那么我们这次就可以直接从S1第3位开始匹配

具体过程点这里

例题:传送门

题意:

t组输入,给你一个模式串ptr,让你找出来它在str中出现的次数

题解:

利用KMP算法,只需要在kmp原来的基础上稍微改一下就可以用来求次数

  1. 1 #include<stdio.h>
  2. 2 #include<string.h>
  3. 3 #include<iostream>
  4. 4 #include<algorithm>
  5. 5 using namespace std;
  6. 6 const int maxn=1000005;
  7. 7 const int INF=0x3f3f3f3f;
  8. 8 char str[maxn],ptr[maxn];
  9. 9 int ans;
  10. 10 void get_next(int len,int *next)
  11. 11 {
  12. 12 next[0]=-1;
  13. 13 int k=-1;
  14. 14 for(int i=1;i<=len-1;++i)
  15. 15 {
  16. 16 while(k>-1 && ptr[k+1]!=ptr[i])
  17. 17 k=next[k];
  18. 18 if(ptr[k+1]==ptr[i])
  19. 19 {
  20. 20 k+=1;
  21. 21 }
  22. 22 next[i]=k;
  23. 23 }
  24. 24 }
  25. 25 void kmp(int slen,int plen)
  26. 26 {
  27. 27 int next[plen]; //这个next数组长度只能定义plen个长度,大的话会出错
  28. 28 get_next(plen,next);
  29. 29 int k=-1;
  30. 30 for(int i=0;i<slen;++i)
  31. 31 {
  32. 32 while(k>-1 && ptr[k+1]!=str[i])
  33. 33 {
  34. 34 k=next[k];
  35. 35 }
  36. 36 if(ptr[k+1]==str[i])
  37. 37 {
  38. 38 k=k+1;
  39. 39 }
  40. 40 if(k==plen-1)
  41. 41 {
  42. 42 ans++;
  43. 43 k=next[k];
  44. 44 //i=i-plen+1+1;
  45. 45 }
  46. 46 }
  47. 47 }
  48. 48 int main()
  49. 49 {
  50. 50 int t;
  51. 51 scanf("%d",&t);
  52. 52 while(t--)
  53. 53 {
  54. 54 ans=0;
  55. 55 scanf("%s%s",ptr,str);
  56. 56 int slen=strlen(str);
  57. 57 int plen=strlen(ptr);
  58. 58 kmp(slen,plen);
  59. 59 printf("%d\n",ans);
  60. 60 }
  61. 61 return 0;
  62. 62 }

有些题目利用next数组的特性来做,比如G - Seek the Name, Seek the Fame

这道题目需要找出来模式串中前后缀的所有相同长度,而不只是求最长

比如“alala”,它的最长相同前后缀是“ala”,但是还有“a”。等到把所有前后缀相同长度输出之后,再输出一下模式串长度就可以了。

  1. 1 #include<stdio.h>
  2. 2 #include<string.h>
  3. 3 #include<iostream>
  4. 4 #include<algorithm>
  5. 5 using namespace std;
  6. 6 const int maxn=400005;
  7. 7 const int INF=0x3f3f3f3f;
  8. 8 char ptr[maxn];
  9. 9 int w[maxn];
  10. 10 void get_next(int len,int *next)
  11. 11 {
  12. 12 next[0]=-1;
  13. 13 int k=-1;
  14. 14 for(int i=1;i<=len-1;++i)
  15. 15 {
  16. 16 while(k>-1 && ptr[k+1]!=ptr[i])
  17. 17 k=next[k];
  18. 18 if(ptr[k+1]==ptr[i])
  19. 19 {
  20. 20 k+=1;
  21. 21 }
  22. 22 next[i]=k;
  23. 23 }
  24. 24 }
  25. 25 int main()
  26. 26 {
  27. 27 int n;
  28. 28 while(~scanf("%s",ptr))
  29. 29 {
  30. 30 int len=strlen(ptr);
  31. 31 int next[len];
  32. 32 get_next(len,next);
  33. 33 int g=0,k=next[len-1];
  34. 34 //w[g++]=next[len-1]+1;
  35. 35 while(k>=0)
  36. 36 {
  37. 37 w[g++]=k+1;
  38. 38 k=next[k];
  39. 39
  40. 40 }
  41. 41 sort(w,w+g);
  42. 42 for(int i=0;i<g;++i)
  43. 43 if(w[i]!=w[i-1] && i!=0)
  44. 44 printf("%d ",w[i]);
  45. 45 else if(i==0) printf("%d ",w[i]);
  46. 46 printf("%d\n",len);
  47. 47 }
  48. 48 return 0;
  49. 49 }

扩展kmp:

扩展KMP求的是对于原串S1的每一个后缀子串与模式串S2的最长公共前缀。它有一个next[]数组和一个extend[]数组。

next[i]表示为模式串S2中以i为起点的后缀字符串和模式串S2的最长公共前缀长度.

extend[i]表示为以字符串S1中以i为起点的后缀字符串和模式串S2的最长公共前缀长度.

复杂度:拓展kmp算法的总体复杂度为O(n+m)的。其中n为母串的长度,m为子串的长度。

算法过程:

S1=aaabaaaaaab
S2=aaaaab
第一步,我们先对原串S1和模式串S2进行逐一匹配,直到发生不配对的情况。我们可以看到,S1[0]=S2[0],S1[1]=S2[1],S1[2]=S2[2],S1[3] ≠S2[3],此时匹配失败,第一步结束,我们得到S1[0,2]=S2[0,2],即extend[0]=3;
Extend[0]的计算如第一步所示,那么extend[1]的计算是否也要从原串S1的1位置,模式串的0位置开始进行逐一匹配呢?扩展KMP优化的便是这个过程。从extend[0]=3的结果中,我们可以知道,S1[0,2]=S2[0,2],那么S1[1.2]=S2[1,2]。因为next[1]=4,所以S2[1,4]=S2[0,3],即S2[1,2]=S[0,1],可以得出S1[1,2]=S2[1,2]=S2[0,1],然后我们继续匹配,S1[3] ≠S2[3],匹配失败,extend[1]=2;
之后也这样
 

给出n组询问,每一组询问包含两个字符串t s,问s中是否包含t。(t中有’?’,’?’可以代替任何字符)。

  1. 1 #include<iostream>
  2. 2 #include<cstring>
  3. 3 #include<cstdio>
  4. 4 #include<string>
  5. 5 #include<algorithm>
  6. 6 using namespace std;
  7. 7 int l1,l2,n;
  8. 8 char s[100009],t[100009];
  9. 9 int nxt[100009];
  10. 10 void next_make()
  11. 11 {
  12. 12 int t1=0,t2=-1;
  13. 13 nxt[0]=-1;
  14. 14 while(t1<l1)
  15. 15 {
  16. 16 if(t2==-1||t[t1]==t[t2]||t[t2]=='?') nxt[++t1]=++t2;
  17. 17 else t2=nxt[t2];
  18. 18 }
  19. 19 }
  20. 20 void match(int t1,int t2)
  21. 21 {
  22. 22 while(t1<l1&&t2<l2)
  23. 23 {
  24. 24 if(t1==-1||t[t1]==s[t2]||t[t1]=='?') t1++,t2++;
  25. 25 else t1=nxt[t1];
  26. 26 }
  27. 27 if(t1==l1) printf("God bless You!\n");
  28. 28 else printf("Game Over!\n");
  29. 29 return;
  30. 30 }
  31. 31 int main()
  32. 32 {
  33. 33 scanf("%d",&n);
  34. 34 while(n--)
  35. 35 {
  36. 36 cin>>t;cin>>s;
  37. 37 l1=strlen(t);
  38. 38 l2=strlen(s);
  39. 39 next_make();
  40. 40 match(0,0);
  41. 41 }
  42. 42 return 0;
  43. 43 }

例题:给一堆字符串,求最长公共字串。

找一个最短的串,暴力求出每一个后缀,和所有串匹配,找到每个extend里最大的,取总体最小,是一个答案,找到所有答案里长度最长的字典序最小的,就是答案。

  1. 1 #define ll long long
  2. 2 #define db double
  3. 3 #define ioss ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
  4. 4 using namespace std;
  5. 5 int n,cnt;
  6. 6 ll ext[220],nex[220];
  7. 7 string skr[4020];
  8. 8 string ans[4020];
  9. 9 void getNext(string &strp,ll nextt[])
  10. 10 {
  11. 11 ll pl=strp.size();
  12. 12 ll fir=0,las=0;
  13. 13 nextt[0]=pl;
  14. 14 for(ll i=1; i<pl; i++)
  15. 15 {
  16. 16 nextt[i] = min(las - i + 1, nextt[i - fir]);
  17. 17 if (nextt[i] < 0) nextt[i] = 0;
  18. 18 while (i+nextt[i]<pl && strp[nextt[i]] == strp[i + nextt[i]])
  19. 19 {
  20. 20 nextt[i]++;
  21. 21 }
  22. 22 if (i + nextt[i] - 1 > las)
  23. 23 {
  24. 24 las = i + nextt[i] - 1;
  25. 25 fir = i;
  26. 26 }
  27. 27 }
  28. 28 }
  29. 29 void exKMP(string &strp,string &strs,ll nextt[],ll extt[])
  30. 30 {
  31. 31 getNext(strp,nextt);
  32. 32 ll pl=strp.size(),sl=strs.size();
  33. 33 ll fir=0,las=-1,mnl=min(sl,pl);
  34. 34 while(las<mnl-1&&strp[las+1]==strs[las+1])
  35. 35 {
  36. 36 las++;
  37. 37 }
  38. 38 extt[0]=las+1;
  39. 39 for(ll i=1; i<sl; i++)
  40. 40 {
  41. 41 extt[i]=min(las-i+1,nextt[i-fir]);
  42. 42 if(extt[i]<0) extt[i]=0;
  43. 43 while(extt[i]<pl && i+extt[i]<sl && strp[extt[i]]==strs[i+extt[i]])
  44. 44 {
  45. 45 extt[i]++;
  46. 46 }
  47. 47 if(i+extt[i]-1>las)
  48. 48 {
  49. 49 las=i+extt[i]-1;
  50. 50 fir=i;
  51. 51 }
  52. 52 }
  53. 53 }
  54. 54 int main()
  55. 55 {
  56. 56 while(scanf("%d",&n)==1&&n)
  57. 57 {
  58. 58 cnt=0;
  59. 59 int mnlen=300,mnlenx;
  60. 60 for(int i=1; i<=n; i++)
  61. 61 {
  62. 62 cin >> skr[i];
  63. 63 if (skr[i].size() < mnlen)
  64. 64 {
  65. 65 mnlen = skr[i].size();
  66. 66 mnlenx = i;
  67. 67 }
  68. 68 }
  69. 69 for(int i=0; i<skr[mnlenx].size(); i++)
  70. 70 {
  71. 71 ll mn=1e10;
  72. 72 string cur=skr[mnlenx].substr(i);
  73. 73 for(int j=1; j<=n; j++)
  74. 74 {
  75. 75 ll mx=0;
  76. 76 exKMP(cur,skr[j],nex,ext);
  77. 77 for(int k=0; k<skr[j].size(); k++)
  78. 78 {
  79. 79 mx=max(mx,ext[k]);
  80. 80 }
  81. 81 mn=min(mn,mx);
  82. 82 }
  83. 83 if(mn>0)
  84. 84 {
  85. 85 if(cnt==0||(mn==ans[1].size()))
  86. 86 {
  87. 87 ans[++cnt]=cur.substr(0,mn);
  88. 88 }
  89. 89 else if(mn>ans[1].size())
  90. 90 {
  91. 91 cnt=0;
  92. 92 ans[++cnt]=cur.substr(0,mn);
  93. 93 }
  94. 94 }
  95. 95 }
  96. 96 if(cnt)
  97. 97 {
  98. 98 sort(ans+1,ans+1+cnt);
  99. 99 cout<<ans[1]<<endl;
  100. 100 }
  101. 101 else cout<<"IDENTITY LOST"<<endl;
  102. 102 }
  103. 103 return 0;
  104. 104 }

Manacher算法:

当我们遇到字符串为“aaaaaaaaa”,之前的算法就会发生各个回文相互重叠的情况,会产生重复计算,然后就产生了一个问题,能否改进?答案是能,1975年,一个叫Manacher发明了Manacher Algorithm算法,俗称马拉车算法,其时间复杂为O(n)。

例题:

HDU - 3613

给你一个字符串(仅含字母),每个字母有一个价值,把字符串切断成两部分,若其中一部分为回文串,则其价值等于各字母价值和相加;否则为0。总价值为两部分价值相加,求最大价值。

题解:

先用manacher求出回文子串长度,再枚举切割点,若切后子串的中点是回文中心,且回文长度扩展到i点,则这个子串为回文,记录价值。最后输出最大价值。

代码:

  1. 1 #include<stdio.h>
  2. 2 #include<string.h>
  3. 3 #include<iostream>
  4. 4 #include<queue>
  5. 5 #include<algorithm>
  6. 6 using namespace std;
  7. 7 const int maxn=5e5+10;
  8. 8 char str[maxn*2],s[maxn];
  9. 9 int len,Len[maxn*2],val[maxn],v[30];
  10. 10 void init()
  11. 11 {
  12. 12 memset(str,0,sizeof(str));
  13. 13 int k=0;
  14. 14 str[k++]='$';
  15. 15 for(int i=1;i<=len;++i)
  16. 16 {
  17. 17 str[k++]='#';
  18. 18 str[k++]=s[i];
  19. 19 }
  20. 20 str[k++]='#';
  21. 21 len=k;
  22. 22 }
  23. 23 void manacher()
  24. 24 {
  25. 25 Len[0]=0;
  26. 26 int sum=0;
  27. 27 int id,mx=0;
  28. 28 for(int i=1;i<len;++i)
  29. 29 {
  30. 30 if(i<mx) Len[i]=min(mx-i,Len[2*id-i]);
  31. 31 else Len[i]=1;
  32. 32 while(str[i-Len[i]]==str[i+Len[i]]) Len[i]++;
  33. 33 if(Len[i]+i>mx)
  34. 34 {
  35. 35 mx=Len[i]+i;
  36. 36 id=i;
  37. 37 }
  38. 38 }
  39. 39 }
  40. 40 int main()
  41. 41 {
  42. 42 int t;
  43. 43 scanf("%d",&t);
  44. 44 while(t--)
  45. 45 {
  46. 46 for(int i=0;i<26;++i)
  47. 47 scanf("%d",&v[i]);
  48. 48 scanf("%s",s+1);
  49. 49 len=strlen(s+1);
  50. 50 for(int i=1;i<=len;++i)
  51. 51 {
  52. 52 val[i]=val[i-1]+v[s[i]-'a'];
  53. 53 }
  54. 54 int n=len;
  55. 55 init();
  56. 56 manacher();
  57. 57 int ans=0;
  58. 58 for(int i = 1; i < n; i++){
  59. 59 int tmp = 0;
  60. 60 if(Len[i + 1] - 1 == i){
  61. 61 if(i % 2){
  62. 62 tmp += val[i / 2] * 2 + v[s[(i + 1) / 2] - 'a'];
  63. 63 }
  64. 64 else{
  65. 65 tmp += val[i / 2] * 2;
  66. 66 }
  67. 67 }
  68. 68 if(Len[i + n + 1] - 1 == n - i){
  69. 69 if((n - i) % 2){
  70. 70 tmp += (val[i + (n - i) / 2] - val[i]) * 2 + v[s[i + (n + 1- i) / 2] - 'a'];
  71. 71 }
  72. 72 else{
  73. 73 tmp += (val[i + (n - i) / 2] - val[i]) * 2;
  74. 74 }
  75. 75 }
  76. 76 ans = max(ans, tmp);
  77. 77 }
  78. 78 printf("%d\n",ans);
  79. 79 }
  80. 80 return 0;
  81. 81 }

板子:

  1. 1 /* 这是一个板子
  2. 2 #include<iostream>
  3. 3 #include<string>
  4. 4 #include<cstring>
  5. 5 #include<algorithm>
  6. 6 #include<vector>
  7. 7 #include<cmath>
  8. 8 using namespace std;
  9. 9 //算法主体
  10. 10 int maxLcsplength(string str) {
  11. 11 //空字符串直接返回0
  12. 12 if (str.length() == 0) {
  13. 13 return 0;
  14. 14 }
  15. 15 //记录下manacher字符串的长度,方便后面使用
  16. 16 int len = (int)(str.length() * 2 + 1);
  17. 17 //开辟动态数组chaArr记录manacher化的字符串
  18. 18 //开辟动态数组pArr记录每个位置的回文半径
  19. 19 char *chaArr = new char[len];
  20. 20 int* pArr = new int[len];
  21. 21 int index = 0;
  22. 22 for (int i = 0; i < len;i++) {
  23. 23 chaArr[i] = (i & 1) == 0 ? '#' : str[index++];
  24. 24 }
  25. 25 //到此完成对原字符串的manacher化
  26. 26 //R是最右回文边界,C是R对应的最左回文中心,maxn是记录的最大回文半径
  27. 27 int R = -1;
  28. 28 int C = -1;
  29. 29 int maxn = 0;
  30. 30 //开始从左到右遍历
  31. 31 for (int i = 0; i < len; i++) {
  32. 32 //第一步直接取得可能的最短的回文半径,当i>R时,最短的回文半径是1,反之,最短的回文半径可能是i对应的i'的回文半径或者i到R的距离
  33. 33 pArr[i] = R > i ? min(R - i, pArr[2 * C - i]) : 1;
  34. 34 //取最小值后开始从边界暴力匹配,匹配失败就直接退出
  35. 35 while (i + pArr[i]<len && i - pArr[i]>-1) {
  36. 36 if (chaArr[i + pArr[i]] == chaArr[i - pArr[i]]) {
  37. 37 pArr[i]++;
  38. 38 }
  39. 39 else {
  40. 40 break;
  41. 41 }
  42. 42 }
  43. 43 //观察此时R和C是否能够更新
  44. 44 if (i + pArr[i] > R) {
  45. 45 R = i + pArr[i];
  46. 46 C = i;
  47. 47 }
  48. 48 //更新最大回文半径的值
  49. 49 maxn = max(maxn, pArr[i]);
  50. 50 }
  51. 51 //记得清空动态数组哦
  52. 52 delete[] chaArr;
  53. 53 delete[] pArr;
  54. 54 //这里解释一下为什么返回值是maxn-1,因为manacherstring的长度和原字符串不同,所以这里得到的最大回文半径其实是原字符串的最大回文子串长度加1,有兴趣的可以自己验证试试
  55. 55 return maxn - 1;
  56. 56 }
  57. 57 int main()
  58. 58 {
  59. 59 string s1 = "";
  60. 60 cout << maxLcsplength(s1) << endl;
  61. 61 string s2 = "abbbca";
  62. 62 cout << maxLcsplength(s2) << endl;
  63. 63 return 0;
  64. 64 }
  65. 65 */
  66. 66
  67. 67
  68. 68 /*
  69. 69 #include<stdio.h>
  70. 70 #include<string.h>
  71. 71 #include<iostream>
  72. 72 #include<queue>
  73. 73 #include<algorithm>
  74. 74 using namespace std;
  75. 75 const int maxn=5e5+10;
  76. 76 char str[maxn*2],s[maxn];
  77. 77 int len,Len[maxn*2],val[maxn],v[30];
  78. 78 void init()
  79. 79 {
  80. 80 memset(str,0,sizeof(str));
  81. 81 int k=0;
  82. 82 str[k++]='$';
  83. 83 for(int i=1;i<=len;++i)
  84. 84 {
  85. 85 str[k++]='#';
  86. 86 str[k++]=s[i];
  87. 87 }
  88. 88 str[k++]='#';
  89. 89 len=k;
  90. 90 }
  91. 91 void manacher()
  92. 92 {
  93. 93 Len[0]=0;
  94. 94 int sum=0;
  95. 95 int id,mx=0;
  96. 96 for(int i=1;i<len;++i)
  97. 97 {
  98. 98 if(i<mx) Len[i]=min(mx-i,Len[2*id-i]);
  99. 99 else Len[i]=1;
  100. 100 while(str[i-Len[i]]==str[i+Len[i]]) Len[i]++;
  101. 101 if(Len[i]+i>mx)
  102. 102 {
  103. 103 mx=Len[i]+i;
  104. 104 id=i;
  105. 105 }
  106. 106 }
  107. 107 }
  108. 108 int main()
  109. 109 {
  110. 110 int t;
  111. 111 scanf("%d",&t);
  112. 112 while(t--)
  113. 113 {
  114. 114 for(int i=0;i<26;++i)
  115. 115 scanf("%d",&v[i]);
  116. 116 scanf("%s",s+1);
  117. 117 len=strlen(s+1); //3
  118. 118
  119. 119 //printf("%d**\n",len); //3
  120. 120 //init();
  121. 121 //manacher();
  122. 122 //printf("%d**\n",len); //8,这个是字符串处理完之后的长度
  123. 123 //for(int i=0;i<=len;++i){
  124. 124 // printf("%d %d\n",i,Len[i]);
  125. 125 //}
  126. 126
  127. 127
  128. 128 for(int i=1;i<=len;++i)
  129. 129 {
  130. 130 val[i]=val[i-1]+v[s[i]-'a'];
  131. 131 }
  132. 132 int n=len;
  133. 133 init();
  134. 134 manacher();
  135. 135 int ans=0;
  136. 136 for(int i = 1; i < n; i++){
  137. 137 int tmp = 0;
  138. 138 if(Len[i + 1] - 1 == i){
  139. 139 if(i % 2){
  140. 140 tmp += val[i / 2] * 2 + v[s[(i + 1) / 2] - 'a'];
  141. 141 }
  142. 142 else{
  143. 143 tmp += val[i / 2] * 2;
  144. 144 }
  145. 145 }
  146. 146 if(Len[i + n + 1] - 1 == n - i){
  147. 147 if((n - i) % 2){
  148. 148 tmp += (val[i + (n - i) / 2] - val[i]) * 2 + v[s[i + (n + 1- i) / 2] - 'a'];
  149. 149 }
  150. 150 else{
  151. 151 tmp += (val[i + (n - i) / 2] - val[i]) * 2;
  152. 152 }
  153. 153 }
  154. 154 ans = max(ans, tmp);
  155. 155 }
  156. 156 printf("%d\n",ans);
  157. 157
  158. 158 }
  159. 159 return 0;
  160. 160 }
  161. 161 */
  162. 162
  163. 163
  164. 164
  165. 165 /*
  166. 166
  167. 167 #include <cstdio>
  168. 168
  169. 169 #include <cmath>
  170. 170
  171. 171 #include <cstring>
  172. 172
  173. 173 #include <cstdlib>
  174. 174
  175. 175 #include <iostream>
  176. 176
  177. 177 #include <algorithm>
  178. 178
  179. 179 #include <queue>
  180. 180
  181. 181 #include <stack>
  182. 182
  183. 183 using namespace std;
  184. 184
  185. 185 char a[51000005];
  186. 186
  187. 187 char s[102000005];
  188. 188
  189. 189 int p[51000005];
  190. 190
  191. 191 int maxp,p0,l;
  192. 192
  193. 193 int ans=1;
  194. 194
  195. 195 void manacher()
  196. 196
  197. 197 {
  198. 198
  199. 199 for(int i=1;i<l;i++)
  200. 200
  201. 201 {
  202. 202
  203. 203 if(i<maxp)
  204. 204
  205. 205 {
  206. 206
  207. 207 int j=(p0<<1)-i;
  208. 208
  209. 209 p[i]=min(p[j],p[p0]+p0-i);
  210. 210
  211. 211 }else
  212. 212
  213. 213 {
  214. 214
  215. 215 p[i]=1;
  216. 216
  217. 217 }
  218. 218
  219. 219 while(s[i-p[i]]==s[i+p[i]])
  220. 220
  221. 221 {
  222. 222
  223. 223 p[i]++;
  224. 224
  225. 225 }
  226. 226
  227. 227 if(i+p[i]>maxp)
  228. 228
  229. 229 {
  230. 230
  231. 231 p0=i;
  232. 232
  233. 233 maxp=i+p[i];
  234. 234
  235. 235 }
  236. 236
  237. 237 }
  238. 238
  239. 239 }
  240. 240
  241. 241 int main()
  242. 242
  243. 243 {
  244. 244
  245. 245 scanf("%s",a+1);
  246. 246
  247. 247 l=strlen(a+1);
  248. 248
  249. 249 p[1]=1;
  250. 250
  251. 251 s[0]=s[1]='#';
  252. 252
  253. 253 for(int i=1;i<=l;i++)
  254. 254
  255. 255 {
  256. 256
  257. 257 s[2*i]=a[i];
  258. 258
  259. 259 s[2*i+1]='#';
  260. 260
  261. 261 }
  262. 262
  263. 263 l=(l<<1)+2;
  264. 264
  265. 265 s[l]='0';
  266. 266
  267. 267 manacher();
  268. 268
  269. 269 for(int i=1;i<=l;i++)
  270. 270
  271. 271 {
  272. 272
  273. 273 ans=max(ans,p[i]-1);
  274. 274
  275. 275 }
  276. 276
  277. 277 printf("%d\n",ans);
  278. 278
  279. 279 return 0;
  280. 280
  281. 281 }
  282. 282
  283. 283 */ 板子

KMP && Manacher && 扩展KMP整理的更多相关文章

  1. Manacher模板,kmp,扩展kmp,最小表示法模板

    *N]; //储存临时串 *N];//中间记录 int Manacher(char tmp[]) { int len=strlen(tmp); ; ;i<len;i++) { s[cnt++]= ...

  2. KMP和扩展KMP【转】

    这种东西基本上在纸上自己推导一下就能做出来XD 转发注明出处 KMP 给出两个字符串A(称为模板串)和B(称为子串),长度分别为lenA和lenB,要求在线性时间内,对于每个A[i] (0<=i ...

  3. KMP与扩展KMP

    原文转自:http://www.cppblog.com/MatoNo1/archive/2011/04/17/144390.aspx KMP:给出两个字符串A(称为模板串)和B(称为子串),长度分别为 ...

  4. KMP 、扩展KMP、Manacher算法 总结

    一. KMP 1 找字符串x是否存在于y串中,或者存在了几次 HDU1711 Number Sequence HDU1686 Oulipo HDU2087 剪花布条 2.求多个字符串的最长公共子串 P ...

  5. 666 专题三 KMP &#38; 扩展KMP &#38; Manacher

    KMP: Problem A.Number Sequence d.求子串首次出现在主串中的位置 s. c. #include<iostream> #include<stdio.h&g ...

  6. KMP和扩展KMP

    文章网上太多这里提一下代码细节: KMP: scanf("%s\n",s); scanf("%s\n",t); int ls=strlen(s),lt=strl ...

  7. kmp模板 && 扩展kmp模板

    kmp模板: #include <bits/stdc++.h> #define PB push_back #define MP make_pair using namespace std; ...

  8. 【kmp或扩展kmp】HDU 6153 A Secret

    acm.hdu.edu.cn/showproblem.php?pid=6153 [题意] 给定字符串A和B,求B的所有后缀在A中出现次数与其长度的乘积之和 A和B的长度最大为1e6 方法一:扩展kmp ...

  9. kmp与扩展kmp模板

    kmp 1 #include <algorithm> 2 #include <iostream> 3 #include <cstring> 4 #include & ...

随机推荐

  1. 根据业务摸索出的一个selenium代码模版(python)

    前言 总算入行上班几个月了,不得不说业务是真的不消停啊.. 本人工作上经常遇到一种场景:为甲方做自动化接口处理工具,登录需要短信验证码,, 嘛算是摸索出了一套selenium代码模板,主要解决如下痛点 ...

  2. centos7下 开启/关闭/查看firewall运行状态命令

    1.开启防火墙:systemctl start firewalld.service [root@localhost bin]# systemctl start firewalld.service [r ...

  3. [Usaco2007 Jan]Balanced Lineup 飞盘比赛

    题目描述 每天,农夫 John 的N(1 <= N <= 50,000)头牛总是按同一序列排队. 有一天, John 决定让一些牛们玩一场飞盘比赛. 他准备找一群在对列中为置连续的牛来进行 ...

  4. JS编写的科学计算器

    最近半个月编写了一个JS+CSS+HTML的网页计算器,从最初的具有简陋界面的简单计算器改版到最终具有科学/标准计算器转换功能并且界面非常友好的计算器,收获良多!总的来说,代码简单,通俗易读,下面贴上 ...

  5. 前端面试之ES6中的继承!

    前端面试之ES6中的继承! ES6之前并没有给我们提供 extends继承.我们可以通过构造函数+原型对象模拟实现继承,被称为组合继承. 1 call() 两个作用: 1 调用这个函数! 2 修改函数 ...

  6. CSSmargin击穿问题(子元素margin-top会影响父元素)

    最近写一个H5页面的时候发现了这个被忽视的问题,一时没想到什么原因,搜了半天,记录一下,方便他人踩坑.唉,有些东西不用就忘. 一.问题描述 <div class="container& ...

  7. 数据库内核——基于HLC的分布式事务实现深度剖析

    DTCC 2019 | 深度解码阿里数据库实现 数据库内核--基于HLC的分布式事务实现深度剖析-阿里云开发者社区 https://developer.aliyun.com/article/70355 ...

  8. 权限过大 ssh协议通过pem文件登陆

    root@oneweek:~# ssh -i uat.pem root@110.5.15.6@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ...

  9. ByteDance 2019 春招题目

    牛客网字节跳动笔试真题:https://www.nowcoder.com/test/16516564/summary 分了 2 次做,磕磕碰碰才写完,弱鸡悲鸣. 1. 聪明的编辑 题目:Link . ...

  10. UVA11694 Gokigen Naname题解

    目录 写在前面 Solution Code 写在前面 UVA的题需要自己读入一个 \(T\) 组数据,别被样例给迷惑了 Solution 每个格子只有两种填法且 \(n \le 7\),暴力搜索两种填 ...