HDU 3068 &&HDU 3294 +最長回文串*3—— manacher/擴展KMP/DP
阿新 • • 發佈:2017-08-24
true font get span while spa 更新 如果 str
HDU 3068 http://acm.hdu.edu.cn/showproblem.php?pid=3068
HDU 3294http://acm.hdu.edu.cn/showproblem.php?pid=3294
擴展KMP:https://segmentfault.com/a/1190000008663857
感覺DP相對實現起來更簡潔一些,很容易想到,可以用bool dp[i][j]:表示從i到j是否為回文串,然後最長長度用一個變量記錄就好
如果dp[i][j]為回文串,那麽dp[i+1][j-1]必為回文串且s[i]==s[j],所以可以得到遞推關系
if(dp[i+1]][j-1]&&s[i]==s[j]) dp[i][j]=1; maxlen=max(maxlen,i-j+1);
但是上述判斷條件並不對……上面的條件漏掉了一個單個字符必為回文串的情況,第二個判斷條件再加一個||j-i<2即可,或者最開始初始化dp數組的時候把i==j的部分賦值為true;
模板模板↓↓↓
bool dp[n][n]; string s; int n; int DP()
{ memset(dp, 0, sizeof(dp)); int maxlen = 0; for (int j = 0; j < s.length(); j++) for (int i = j; i >= 0; i--) if(s[i]==s[j]&&(j-i<2|| dp[i + 1][j - 1])) { dp[i][j] = 1; maxlen = max(maxlen, j - i + 1); } return maxlen; }
但是……dp數組這樣開就太大了……相對短一些的字符串還能用,長的就不行了……
manacher
manacher:https://segmentfault.com/a/1190000003914228#articleHeader8
HDU 3086
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; const int MAX = 110000 + 10; char s[MAX*2];//數組要開兩倍的 int rl[MAX*2]; int n,pos,maxlen,maxright; int manacher() { for (int i = n; i >= 0; i--) { s[2 * i + 2] = s[i]; s[2 * i + 1] = ‘#‘; } s[0] = ‘*‘; s[n * 2 + 2] = ‘\0‘; //大佬的小技巧,防止數組越界 for (int i = 2; i < 2 * n + 1; i++) { if (maxright > i) //i在pos左邊 rl[i] = min(rl[2 * pos-i], maxright- i);//i在pos右邊 else rl[i] = 1; while (s[i - rl[i]] == s[i + rl [i]]) rl[i]++; //向兩邊擴展 if (maxright < rl[i]+i - 1) //更新maxright { maxright = rl[i] + i - 1; pos = i; } if (maxlen < rl[i]) maxlen = rl[i]; } return maxlen-1; } int main() { while (scanf("%s", s)!=EOF) { n = strlen(s); maxright = 0; pos = 0; maxlen = 0; printf("%d\n",manacher()); } return 0; }
HDU3298
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; const int MAX = 200000 + 10; int rl[MAX * 2]; char s[MAX * 2],t[MAX*2], a[5]; int len, maxlen, pos, st,maxright,ed; void manacher() { s[0] = ‘*‘; s[2 * len + 2] = ‘\0‘; for (int i = 0; i < len; i++) { s[i * 2 + 1] = ‘#‘; s[i * 2 + 2] = t[i]; } for (int i = 2; i < 2 * len + 2; i++) { if (i < maxright) rl[i] = min(maxright - i, rl[2 * pos - i]); else rl[i] = 1; while (s[i + rl[i]] == s[i - rl[i]]) rl[i]++; if (i + rl[i]-1 > maxright) { maxright = i + rl[i]-1; pos = i; } if (maxlen < rl[i]) { maxlen = rl[i]; st =(i-rl[i])/2; ed = (i + rl[i]) / 2-2; } } maxlen--; } int main() { while (scanf("%s%s",a,t)!= EOF) { //getchar(); len = strlen(t); for (int i = 0; i < len; i++) { int b = t[i] - a[0]; if (b < 0) b += 26; t[i] = b + ‘a‘; } maxlen = 0; maxright = 0; pos = 0; st = 0; ed = 0; manacher(); if (maxlen==1)printf("No solution!"); else { printf("%d %d\n", st, ed); for (int i = st; i <= ed; i++) printf("%c",t[i] ); } puts(""); } return 0; }
擴展KMP
emmmmmmm……還不太會……先放著,會了再更
HDU 3068 &&HDU 3294 +最長回文串*3—— manacher/擴展KMP/DP