Panlindromic Tree(回文树)的四个例题
http://www.tsinsen.com/new/A1280
双回文串,正着做一遍,倒着做一遍,维护每个节点 向前向后的最长回文子串长度(len[ last ])
1 #include <bits/stdc++.h> 2 const long long mod = 1e9+7; 3 const double ex = 1e-10; 4 #define inf 0x3f3f3f3f 5 using namespace std; 6 const int MAXN = 212345; 7 const int N = 26; 8 struct Palindromic_Tree{ 9 int next[MAXN][N]; 10 int fail[MAXN]; 11 int cnt[MAXN]; 12 int num[MAXN]; 13 int len[MAXN]; 14 int S[MAXN]; 15 int last; 16 int n; 17 int p; 18 int newnode(int l){ 19 for (int i = 0 ; i<N; i++) next[p][i] = 0; 20 cnt[p] = 0; 21 num[p] = 0; 22 len[p] = l; 23 return p++; 24 } 25 void init(){ 26 p = 0; 27 newnode(0); 28 newnode(-1); 29 last = 0; 30 n = 0; 31 S[n] = -1; 32 fail[0] = 1; 33 } 34 int get_fail(int x){ 35 while (S[n-len[x]-1] != S[n]) x = fail[x]; 36 return x; 37 } 38 int add(int c){ 39 c-='a'; 40 S[++n] = c; 41 int cur = get_fail(last); 42 if (!next[cur][c]){ 43 int now = newnode(len[cur] + 2); 44 fail[now] = next[get_fail(fail[cur])][c]; 45 next[cur][c] = now; 46 num[now] = num[fail[now]] + 1; 47 } 48 last = next[cur][c]; 49 cnt[last]++; 50 return len[last]; 51 } 52 void count(){ 53 for (int i = p-1 ; i >= 0; i--) cnt[fail[i]] += cnt[i]; 54 } 55 }; 56 Palindromic_Tree a; 57 int len[212345]; 58 int main() 59 { 60 string s; 61 cin >> s; 62 int l = s.length(); 63 a.init(); 64 for (int i = 0 ; i<l ; i++){ 65 len[i] = a.add(s[i]); 66 } 67 a.init(); 68 int ans = 0; 69 for (int i = l-1; i>=1 ;i--){ 70 ans = max(ans , len[i-1] + a.add(s[i])); 71 } 72 cout << ans << endl; 73 return 0; 74 }
http://www.tsinsen.com/new/A1255
可以把每种串的 数目和长度存下来,按照长度排个序,从大到小维护。
1 #include <bits/stdc++.h> 2 const long long mod = 19930726; 3 const double ex = 1e-10; 4 #define inf 0x3f3f3f3f 5 using namespace std; 6 const int MAXN = 2123456; 7 const int N = 26; 8 struct Palindromic_Tree{ 9 int next[MAXN][N]; 10 int fail[MAXN]; 11 int cnt[MAXN]; 12 int num[MAXN]; 13 int len[MAXN]; 14 int S[MAXN]; 15 int last; 16 int n; 17 int p; 18 int newnode(int l){ 19 for (int i = 0 ; i<N; i++) next[p][i] = 0; 20 cnt[p] = 0; 21 num[p] = 0; 22 len[p] = l; 23 return p++; 24 } 25 void init(){ 26 p = 0; 27 newnode(0); 28 newnode(-1); 29 last = 0; 30 n = 0; 31 S[n] = -1; 32 fail[0] = 1; 33 } 34 int get_fail(int x){ 35 while (S[n-len[x]-1] != S[n]) x = fail[x]; 36 return x; 37 } 38 void add(int c){ 39 c-='a'; 40 S[++n] = c; 41 int cur = get_fail(last); 42 if (!next[cur][c]){ 43 int now = newnode(len[cur] + 2); 44 fail[now] = next[get_fail(fail[cur])][c]; 45 next[cur][c] = now; 46 num[now] = num[fail[now]] + 1; 47 } 48 last = next[cur][c]; 49 cnt[last]++; 50 } 51 void count(){ 52 for (int i = p-1 ; i >= 0; i--) cnt[fail[i]] += cnt[i]; 53 } 54 }; 55 Palindromic_Tree a; 56 int len[212345]; 57 typedef pair<int,long long> pii; 58 pii p[1000022]; 59 long long ksm(long long x,long long y){ 60 long long ans = 1; 61 while (y){ 62 if (y % 2) ans = ans * x % mod; 63 x = x*x % mod; 64 y/=2; 65 } 66 return ans; 67 } 68 int main() 69 { 70 string s; 71 int l; 72 long long k; 73 cin >> l >> k; 74 cin >> s; 75 a.init(); 76 for (int i = 0 ; i<l ; i++){ 77 a.add(s[i]); 78 } 79 a.count(); 80 int cnt = 0; 81 for (int i = 2 ; i<a.p ; i++){ 82 if (a.len[i] % 2 == 0) continue; 83 p[cnt++] = make_pair(a.len[i],(long long)a.cnt[i]); 84 } 85 sort(p,p+cnt); 86 long long ans = 1; 87 int i = cnt-1; 88 while (k > 0 && i >= 0){ 89 ans = (ans * ksm((long long)p[i].first,min(p[i].second,k))) % mod; 90 k -= min(k,p[i].second); 91 i--; 92 } 93 if (k > 0){ 94 puts("-1"); 95 } 96 else cout << ans << endl; 97 }
http://www.tsinsen.com/new/A1393
这个题还是CF的17E,貌似回文树不是正解,可能需要马拉车优雅的过,明天学学马拉车写了他吧。
这个题,第一次理解了num的含义,num记录的是每一类回文串的①性质不同,②结尾相同(左对齐)的子串数目。
其中限制条件 性质不同 可以有多种理解,他们 长度 不同 且 左对齐,显然他们性质不同
另外还有,以某个节点为 右端点的所有回文子串 肯定 性质不同。
让求相交的回文串对数 , 可以 反着求,求出总的对数,减去不相交的即可。
1 #include <cstdio> 2 #include <cstring> 3 #include <string> 4 #include <algorithm> 5 #include <iostream> 6 const long long mod = 51123987; 7 const double ex = 1e-10; 8 #define inf 0x3f3f3f3f 9 using namespace std; 10 const int MAXN = 2000009; 11 const int N = 26; 12 struct Palindromic_Tree{ 13 int next[MAXN][N]; 14 int fail[MAXN]; 15 int cnt[MAXN]; 16 int num[MAXN]; 17 int len[MAXN]; 18 short S[MAXN]; 19 int last; 20 int n; 21 int p; 22 int newnode(int l){ 23 for (int i = 0 ; i<N; i++) next[p][i] = 0; 24 cnt[p] = 0; 25 num[p] = 0; 26 len[p] = l; 27 return p++; 28 } 29 void init(){ 30 p = 0; 31 newnode(0); 32 newnode(-1); 33 last = 0; 34 n = 0; 35 S[n] = -1; 36 fail[0] = 1; 37 } 38 int get_fail(int x){ 39 while (S[n-len[x]-1] != S[n]) x = fail[x]; 40 return x; 41 } 42 int add(int c){ 43 c-='a'; 44 S[++n] = c; 45 int cur = get_fail(last); 46 if (!next[cur][c]){ 47 int now = newnode(len[cur] + 2); 48 fail[now] = next[get_fail(fail[cur])][c]; 49 next[cur][c] = now; 50 num[now] = num[fail[now]] + 1; 51 } 52 last = next[cur][c]; 53 cnt[last]++; 54 return num[last]; 55 } 56 long long count(){ 57 for (int i = p-1 ; i >= 0; i--) cnt[fail[i]] += cnt[i]; 58 long long ans = 0; 59 for (int i = 2 ; i<p;i++) 60 ans = (ans + cnt[i])% mod; 61 return ans; 62 } 63 }; 64 Palindromic_Tree a; 65 int sum[2000009]; 66 int main() 67 { 68 string s; 69 int l; 70 cin >> l; 71 cin >> s; 72 a.init(); 73 for (int i = 0 ; i<l ; i++){ 74 sum[i] = a.add(s[i]); 75 } 76 for (int i = 1 ; i<l ;i++){ 77 sum[i] = (sum[i] + sum[i-1]) % mod; 78 } 79 long long ans = a.count(); 80 ans = ans * (ans - 1 ) / 2 % mod; 81 a.init(); 82 for (int i = l-1; i>0 ; i--){ 83 long long x = a.add(s[i]); 84 ans = ((ans - x * sum[i-1]) % mod + mod) % mod; 85 } 86 cout << ans << endl; 87 return 0; 88 }
卡内存卡到死,CF根本过不去,tsinsen也是卡过的。
不过这个题让我深刻理解了num数组的含义
还有一题之前写过的
http://www.cnblogs.com/HITLJR/p/7687885.html
学习回文树,首先把代码看懂,找几个简单的自己模拟一下整个过程,然后理解每个数组的含义,灵活运用add的返回值求一些东西。