manacher算法专题
一、模板
算法解析:http://www.felix021.com/blog/read.php?2040
1 *主要用来解决一个字符串中最长回文串的长度,在O(n)时间内,线性复杂度下,求出以每个字符串为中心的最长回文,奇数回文跟偶数回文一起考虑了 2 S $ # 1 # 2 # 2 # 1 # 2 # 3 # 2 # 1 # 3 P 1 2 1 2 5 2 1 4 1 2 1 6 1 2 1 2 1 4 5 最后所求的值就是max(P[i]-1) 6 7 //输入,并处理得到字符串s,s[0]=$ 8 void getp() 9 { 10 int p[1000], mx = 0, id = 0; 11 memset(p, 0, sizeof(p)); 12 for (i = 1; s[i] != '\0'; i++) 13 { 14 p[i] = mx>i ? min(p[2*id-i], mx-i) : 1; 15 while (s[i + p[i]] == s[i - p[i]]) p[i]++; 16 if (i + p[i] > mx) 17 { 18 mx = i + p[i]; 19 id = i; 20 } 21 } 22 }
二、题目
题意:输入n(1 <= n <= 100000)个人的身高hi(50 <= hi <= 250),从这些人中连续挑出k个人,这k个人【身高是左右对称的,如果是k是奇数,那么中间那个人的身高任意】&&【从左到中间那个人,身高需保证不下降,如果用H表示新队形的高度,则H[1] <= H[2] <= H[3] .... <= H[mid]】,求k的最大值。
解题思路:一般的manacher添加的是’#’,但是本题左半边的身高不递减,所以添加的应该是(h[i]+h[i+1])/2,注意细节。处理后的第奇数个身高是添加上去的,第偶数个身高是一开始输入的,当i-p[i]是奇数时,无论hh[i-p[i]]与hh[i+p[i]]是否相等,p[i]都应该+1。
比如:h[] = 80 60 70 60 90 50 ==> hh[] = -1 65 80 70 60 65 70 65 60 75 90 70 50 65【有颜色的是原串】,以70为中心时,p[6]=4而不是3
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstring> 5 #include <string> 6 using namespace std; 7 const int N=2*1e5+10; 8 int h[N], hh[N]; 9 int t, n; 10 int p[N], lenhh; 11 void getp() 12 { 13 int mx = 0, id = 0; 14 memset(p, 0, sizeof(p)); 15 for (int i = 1; i<lenhh; i++) 16 { 17 p[i] = mx>i ? min(p[2*id-i], mx-i) : 1; 18 while(hh[i + p[i]] == hh[i - p[i]] && hh[i-p[i]]<=hh[i-p[i]+1]) p[i]++; 19 if((i-p[i])%2) p[i]++; 20 if (i + p[i] > mx) 21 { 22 mx = i + p[i]; 23 id = i; 24 } 25 } 26 } 27 int main(){ 28 scanf("%d", &t); 29 while(t--){ 30 scanf("%d", &n); 31 for(int i=1; i<=n; i++){ 32 scanf("%d", &h[i]); 33 } 34 h[0]=h[n], h[n+1]=h[1]; 35 lenhh=2; 36 hh[1]=(h[0]+h[1])/2, hh[0]=-1; 37 for(int i=1; i<=n; i++){ 38 hh[lenhh++]=h[i]; 39 hh[lenhh++]=(h[i]+h[i+1])/2; 40 } 41 // for(int i=0; i<lenhh; i++) cout<<hh[i]<<" "; 42 // cout<<endl; 43 getp(); 44 int maxn=0; 45 // for(int i=0; i<lenhh; i++) cout<<p[i]<<" "; 46 // cout<<endl; 47 for(int i=1; i<lenhh; i++) maxn = max(maxn, p[i]-1); 48 printf("%d\n", maxn); 49 } 50 return 0; 51 }
2、【HDU 3948】The Number of Palindromes(manacher +建图 || )
题意:输入一个字符串(len<=1e5),求这个字符串中不同的回文子串的个数,如:【输入aaaa,有四个不同的回文子串,a、aa、aaa、aaaa】
解题思路:先用计算字符串的hash值,manacher算法求出p[],枚举每一个中心点,从可能的最长回文串的两端逐渐向里判断是否出现过,如果长的出现过了,那短的也一定出现过。判断这个字符串是否出现过目前一共有两种方法:【最后的点的总数不会超过3*1e5的,那就将每一个hash值都对mod(mod=3*1e5+10)取余,建图,hash值%mod后相等的利用head连成一个图】&&【这一种方式就是比较费时但也比较直接的,直接用map判断这个hash值是不是出现过】
Get新技能:将判断字符串是否出现过转化为判断hash值是不是出现过,同时建图判断hash值是否出现过。
manacher+建图
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstring> 5 #include <string> 6 #include <map> 7 using namespace std; 8 9 #define ull unsigned long long 10 #define ll __int64 11 12 const int N = 1e5+10; 13 const ull bas = 311; 14 ull has[N], base[N]; 15 char s[N], ss[2*N]; 16 int lenss, p[2*N]; 17 18 struct hash_map{ 19 const static int mod=3*N+10;//一个静态的、值不能被改变的整型常量 20 int idx, head[mod]; 21 22 struct hash_tables{ 23 int next; 24 ull key; 25 }ele[2*N]; 26 27 void init(){ 28 idx = 0; 29 memset(head, 0xff, sizeof(head));//初始化为-1 30 } 31 32 void clear(){// clear的效率要高于init的效率,后期的用以替换init 33 for(int i=0; i<idx; i++){ 34 head[ele[i].key%mod] = -1; 35 } 36 idx = 0; 37 } 38 39 void insert(ull x){ 40 int tmp = x%mod; 41 ele[idx].key = x; 42 ele[idx].next = head[tmp]; 43 head[tmp] = idx++; 44 } 45 46 bool find(ull x){ 47 int hashcode = x%mod; 48 for(int i=head[hashcode]; i!=-1; i=ele[i].next){ 49 if(ele[i].key == x) return true; 50 } 51 return false; 52 } 53 }hashi; // 将hash表的实现封装成一个类 54 55 ll ans; 56 57 void manacher(){ 58 int mx = 0, id = 0; 59 memset(p, 0, sizeof(p)); 60 for (int i = 1; i<lenss; i++) 61 { 62 p[i] = mx>i ? min(p[2*id-i], mx-i) : 1; 63 while (ss[i + p[i]] == ss[i - p[i]]) p[i]++; 64 if (i + p[i] > mx) 65 { 66 mx = i + p[i]; 67 id = i; 68 } 69 } 70 } 71 void init(){ 72 ss[0] = '$', ss[1] = '#'; 73 lenss = 2, has[0]=0; 74 int len=strlen(s); 75 for(int i=0; i<len; i++){ 76 has[i+1] = has[i]*bas+s[i]-'a'+1; 77 ss[lenss++] = s[i]; 78 ss[lenss++] = '#'; 79 } 80 ss[lenss]='\0'; 81 manacher(); 82 } 83 int begn, ed; 84 void find(int id, int dis){ 85 begn=id-dis+1, ed=id+dis-1; 86 if(begn%2==1) begn++, ed--; 87 while(begn<=ed){ 88 ull k = has[ed/2] - has[begn/2-1]*base[ed/2-begn/2+1]; 89 if(!hashi.find(k)){ 90 hashi.insert(k); 91 ans++; 92 } 93 else break; 94 begn+=2, ed-=2; 95 } 96 } 97 int main(){ 98 int t, cas=1; 99 scanf("%d", &t); 100 hashi.init(); 101 base[0] = 1; 102 for(int i=1; i<N; i++) base[i] = base[i-1]*bas; 103 104 while(t--){ 105 hashi.clear(); 106 scanf("%s", s); 107 init(); 108 109 ans = 0; 110 for(int i=1; i<lenss; i++){ 111 find(i, p[i]); 112 } 113 printf("Case #%d: %I64d\n", cas++, ans); 114 } 115 return 0; 116 }
manacher+map
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstring> 5 #include <string> 6 #include <map> 7 using namespace std; 8 9 #define ull unsigned long long 10 11 const int N = 1e5+10; 12 const ull bas = 311; 13 ull has[N], base[N]; 14 char s[N], ss[2*N]; 15 int lenss, p[2*N]; 16 map<ull, int>mp; 17 18 int ans; 19 20 void manacher(){ 21 int mx = 0, id = 0; 22 memset(p, 0, sizeof(p)); 23 for (int i = 1; ss[i] != '\0'; i++) 24 { 25 p[i] = mx>i ? min(p[2*id-i], mx-i) : 1; 26 while (ss[i + p[i]] == ss[i - p[i]]) p[i]++; 27 if (i + p[i] > mx) 28 { 29 mx = i + p[i]; 30 id = i; 31 } 32 } 33 } 34 void init(){ 35 ss[0] = '$', ss[1] = '#'; 36 lenss = 2, has[0]=0; 37 int len = strlen(s); 38 for(int i=0; i<len; i++){ 39 has[i+1] = has[i]*bas+s[i]-'a'+1; 40 ss[lenss++] = s[i]; 41 ss[lenss++] = '#'; 42 } 43 ss[lenss] = '\0'; 44 manacher(); 45 } 46 int begn, ed; 47 void find(int id, int dis){ 48 begn=id-dis+1, ed=id+dis-1; 49 if(begn%2==1) begn++, ed--; 50 while(begn<=ed){ 51 ull k = has[ed/2] - has[begn/2-1]*base[ed/2-begn/2+1]; 52 if(!mp[k]){ 53 mp[k] = 1; 54 ans++; 55 } 56 else break; 57 begn+=2, ed-=2; 58 } 59 } 60 int main(){ 61 int t, cas=1; 62 scanf("%d", &t); 63 64 base[0] = 1; 65 for(int i=1; i<N; i++) base[i] = base[i-1]*bas; 66 67 while(t--){ 68 scanf("%s", s); 69 init(); 70 71 ans = 0, mp.clear(); 72 for(int i=1; i<lenss; i++){ 73 find(i, p[i]); 74 } 75 printf("Case #%d: %d\n", cas++, ans); 76 } 77 return 0; 78 }