BZOJ4480[JSOI2013]快乐的jyy
*回文自动机第一题*
回文自动机学习地址:https://www.cnblogs.com/nianheng/p/9814530.html
指针版模板地址:https://blog.csdn.net/zp1ng/article/details/80425494
很明显的回文自动机,优秀做法是把两个串插入一个自动机,分别统计数量,统计答案时相同节点上两个数量相乘加入答案。
当然你也可以像我一样不优秀地开两个自动机然后统计答案的时候再开个pair队列,跑得很慢qwq。
网上的题解都是数组版的回文自动机,我来贡献一发指针版吧,代码丑陋不堪 捂脸(/ω\)。
跑得很慢的丑陋的代码↓
1 #include <cstdio> 2 #include <cstring> 3 #include <iomanip> 4 #include <iostream> 5 #include <queue> 6 7 typedef long long LL; 8 struct PalindromeAutomata { 9 struct Node { 10 Node *fail, *next[26]; 11 int len, cnt; 12 } * root0, *root1, *last; 13 int length; 14 char string[50010]; 15 16 PalindromeAutomata(); 17 Node *newNode(int = 0); 18 void init(); 19 void release(); 20 void insert(int); 21 void insert(char *); 22 void pushUp(); 23 } PAM1, PAM2; 24 char s1[50010], s2[50010]; 25 26 LL bfs(); 27 28 int main() { 29 // freopen("4480.in", "r", stdin); 30 // freopen("4480.out", "w", stdout); 31 std::ios::sync_with_stdio(false); 32 std::cin >> s1 >> s2; 33 PAM1.init(); 34 PAM2.init(); 35 PAM1.insert(s1); 36 PAM2.insert(s2); 37 PAM1.pushUp(); 38 PAM2.pushUp(); 39 std::cout << bfs() << std::endl; 40 41 return 0; 42 } 43 PalindromeAutomata::Node *PalindromeAutomata::newNode(int l) { 44 Node *res = new Node(); 45 res->len = l; 46 res->cnt = 0; 47 res->fail = root0; 48 for (int i = 0; i < 26; i++) res->next[i] = root0; 49 return res; 50 } 51 PalindromeAutomata::PalindromeAutomata() { memset(this, 0, sizeof(PalindromeAutomata)); } 52 void PalindromeAutomata::init() { 53 if (root0) release(); 54 root0 = newNode(); 55 for (int i = 0; i < 26; i++) root0->next[i] = root0; 56 root1 = newNode(-1); 57 root0->fail = root1->fail = root1; 58 } 59 void PalindromeAutomata::insert(char *str) { 60 length = 0; 61 last = root0; 62 int l = strlen(str); 63 for (int i = 0; i < l; i++) insert(str[i] - 'A'); 64 } 65 void PalindromeAutomata::insert(int c) { 66 string[++length] = 'A' + c; 67 Node *p = last; 68 while (string[length - p->len - 1] != string[length]) p = p->fail; 69 if (p->next[c] == root0) { 70 Node *np = newNode(p->len + 2), *q = p->fail; 71 while (string[length - q->len - 1] != string[length]) q = q->fail; 72 np->fail = q->next[c]; 73 p->next[c] = np; 74 } 75 last = p->next[c]; 76 last->cnt++; 77 //std::cerr << last->len << std::endl; 78 } 79 void PalindromeAutomata::release() { 80 std::queue<Node *> q; 81 q.push(root0); 82 q.push(root1); 83 while (!q.empty()) { 84 Node *p = q.front(); 85 for (int i = 0; i < 26; i++) 86 if (p->next[i] != root0) q.push(p->next[i]); 87 delete p; 88 } 89 } 90 void PalindromeAutomata::pushUp() { 91 std::vector<Node *> q; 92 q.push_back(root1); 93 q.push_back(root0); 94 for (int i = 0; i < q.size(); i++) 95 for (int j = 0; j < 26; j++) 96 if (q[i]->next[j] != root0) q.push_back(q[i]->next[j]); 97 for (int i = q.size() - 1; i >= 0; i--) q[i]->fail->cnt += q[i]->cnt; 98 } 99 typedef PalindromeAutomata::Node Node; 100 LL bfs() { 101 LL res = 0; 102 std::queue<std::pair<Node *, Node *> > q; 103 q.push(std::make_pair(PAM1.root0, PAM2.root0)); 104 q.push(std::make_pair(PAM1.root1, PAM2.root1)); 105 while (!q.empty()) { 106 std::pair<Node *, Node *> p = q.front(); 107 q.pop(); 108 if (p.first != PAM1.root0 && p.first != PAM1.root1) 109 res += p.first->cnt * 1ll * p.second->cnt; 110 for (int i = 0; i < 26; i++) 111 if (p.first->next[i] != PAM1.root0 && p.second->next[i] != PAM2.root0) 112 q.push(std::make_pair(p.first->next[i], p.second->next[i])); 113 } 114 return res; 115 }