往上偷的板子,用起来蛮不错嘿嘿嘿。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 300005;
const int N = 26;
const int MOD = 1e9 + 7;
struct Palindromic_Tree {int next[MAXN][N];//next指针,next指针和字典树类似,指向的串为当前串两端加上同一个字符构成  int fail[MAXN];//fail指针,失配后跳转到fail指针指向的节点  int cnt[MAXN]; //表示节点i表示的本质不同的串的个数(建树时求出的不是完全的,最后count()函数跑一遍以后才是正确的) int num[MAXN]; //表示以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数int len[MAXN];//len[i]表示节点i表示的回文串的长度(一个节点表示一个回文串)int S[MAXN];//存放添加的字符  int last;//指向新添加一个字母后所形成的最长回文串表示的节点。int n;//表示添加的字符个数。int p;//表示添加的节点个数。int psum[MAXN];//表示以节点i表示的最长回文串的最右端点为回文串结尾的所有回文串的长度和int newnode(int l) {//新建节点  for (int i = 0; i < N; ++i) next[p][i] = 0;cnt[p] = 0;num[p] = 0;len[p] = l;return p++;}void init() {//初始化  p = 0;newnode(0);newnode(-1);last = 0;n = 0;S[n] = -1;//开头放一个字符集中没有的字符,减少特判  fail[0] = 1;psum[0] = 0; psum[1] = 0;}int get_fail(int x) {//和KMP一样,失配后找一个尽量最长的  while (S[n - len[x] - 1] != S[n]) x = fail[x];return x;}void add(int c) {c -= 'a';S[++n] = c;int cur = get_fail(last);//通过上一个回文串找这个回文串的匹配位置  if (!next[cur][c]) {//如果这个回文串没有出现过,说明出现了一个新的本质不同的回文串  int now = newnode(len[cur] + 2);//新建节点  fail[now] = next[get_fail(fail[cur])][c];//和AC自动机一样建立fail指针,以便失配后跳转  next[cur][c] = now;num[now] = num[fail[now]] + 1;psum[now] = ((long long)psum[fail[now]] + len[now]) % MOD;}last = next[cur][c];cnt[last] ++;}void count() {for (int i = p - 1; i >= 0; --i) cnt[fail[i]] += cnt[i];//父亲累加儿子的cnt,因为如果fail[v]=u,则u一定是v的子回文串!  }
};
Palindromic_Tree pam;

HYSBZ - 3676

考虑一个只包含小写拉丁字母的字符串s。我们定义s的一个子串t的“出
现值”为t在s中的出现次数乘以t的长度。请你求出s的所有回文子串中的最
大出现值。

Input

输入只有一行,为一个只包含小写字母(a -z)的非空字符串s。

Output

输出一个整数,为逝查回文子串的最大出现值。

Sample Input

【样例输入l】 abacaba 【样例输入2] www

Sample Output

【样例输出l】 7 【样例输出2] 4

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 300005;
const int N = 26;struct Palindromic_Tree {int next[MAXN][N];//next指针,next指针和字典树类似,指向的串为当前串两端加上同一个字符构成  int fail[MAXN];//fail指针,失配后跳转到fail指针指向的节点  int cnt[MAXN]; //表示节点i表示的本质不同的串的个数(建树时求出的不是完全的,最后count()函数跑一遍以后才是正确的) int num[MAXN]; //表示以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数int len[MAXN];//len[i]表示节点i表示的回文串的长度(一个节点表示一个回文串)int S[MAXN];//存放添加的字符  int last;//指向新添加一个字母后所形成的最长回文串表示的节点。int n;//表示添加的字符个数。int p;//表示添加的节点个数。int newnode(int l) {//新建节点  for (int i = 0; i < N; ++i) next[p][i] = 0;cnt[p] = 0;num[p] = 0;len[p] = l;return p++;}void init() {//初始化  p = 0;newnode(0);newnode(-1);last = 0;n = 0;S[n] = -1;//开头放一个字符集中没有的字符,减少特判  fail[0] = 1;//最好放外面不然好多数组都要清零初始化,比如这个}int get_fail(int x) {//和KMP一样,失配后找一个尽量最长的  while (S[n - len[x] - 1] != S[n]) x = fail[x];return x;}void add(int c) {c -= 'a';S[++n] = c;int cur = get_fail(last);//通过上一个回文串找这个回文串的匹配位置  if (!next[cur][c]) {//如果这个回文串没有出现过,说明出现了一个新的本质不同的回文串  int now = newnode(len[cur] + 2);//新建节点  fail[now] = next[get_fail(fail[cur])][c];//和AC自动机一样建立fail指针,以便失配后跳转  next[cur][c] = now;num[now] = num[fail[now]] + 1;}last = next[cur][c];cnt[last] ++;}void count() {for (int i = p - 1; i >= 0; --i) cnt[fail[i]] += cnt[i];//父亲累加儿子的cnt,因为如果fail[v]=u,则u一定是v的子回文串!  }
};
Palindromic_Tree pam;
int main() {ios::sync_with_stdio(0);cin.tie(0); cout.tie(0);string m; cin >> m;pam.init();for (int i = 0; i < m.length(); i++) {pam.add(m[i]);}pam.count();long long ret = 0;for (int i = 2; i < pam.p; i++) {ret = max((long long)pam.len[i] * pam.cnt[i], ret);}cout << ret << endl;return 0;
}

UVALive - 7041

求a中每个回文串在b中出现的次数的和

奖励两课树,分别作用于a,b,然后进行从节点0和1分别向下dfs即可

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 3600005;
const int N = 26;struct Palindromic_Tree {int next[MAXN][N];//next指针,next指针和字典树类似,指向的串为当前串两端加上同一个字符构成  int fail[MAXN];//fail指针,失配后跳转到fail指针指向的节点  int cnt[MAXN]; //表示节点i表示的本质不同的串的个数(建树时求出的不是完全的,最后count()函数跑一遍以后才是正确的) int num[MAXN]; //表示以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数int len[MAXN];//len[i]表示节点i表示的回文串的长度(一个节点表示一个回文串)int S[MAXN];//存放添加的字符  int last;//指向新添加一个字母后所形成的最长回文串表示的节点。int n;//表示添加的字符个数。int p;//表示添加的节点个数。int newnode(int l) {//新建节点  for (int i = 0; i < N; ++i) next[p][i] = 0;cnt[p] = 0;num[p] = 0;len[p] = l;return p++;}void init() {//初始化  p = 0;newnode(0);newnode(-1);last = 0;n = 0;S[n] = -1;//开头放一个字符集中没有的字符,减少特判  fail[0] = 1;}int get_fail(int x) {//和KMP一样,失配后找一个尽量最长的  while (S[n - len[x] - 1] != S[n]) x = fail[x];return x;}void add(int c) {c -= 'a';S[++n] = c;int cur = get_fail(last);//通过上一个回文串找这个回文串的匹配位置  if (!next[cur][c]) {//如果这个回文串没有出现过,说明出现了一个新的本质不同的回文串  int now = newnode(len[cur] + 2);//新建节点  fail[now] = next[get_fail(fail[cur])][c];//和AC自动机一样建立fail指针,以便失配后跳转  next[cur][c] = now;num[now] = num[fail[now]] + 1;}last = next[cur][c];cnt[last] ++;}void count() {for (int i = p - 1; i >= 0; --i) cnt[fail[i]] += cnt[i];//父亲累加儿子的cnt,因为如果fail[v]=u,则u一定是v的子回文串!  }
};
Palindromic_Tree pam1, pam2;
long long ans = 0;
void dfs(int u, int v) {for (int i = 0; i < 26; i++) {int x = pam1.next[u][i];int y = pam2.next[v][i];if (x && y) {ans += 1LL * pam1.cnt[x] * pam2.cnt[y];dfs(x, y);}}
}
int main() {ios::sync_with_stdio(0);cin.tie(0); cout.tie(0);int te, cas = 1;cin >> te;while(te--){string n, m; cin >> n >> m;pam1.init(); pam2.init(); ans = 0;for (int i = 0; i < n.length(); i++) {pam1.add(n[i]);}for (int j = 0; j < m.length(); j++) {pam2.add(m[j]);}pam1.count(); pam2.count();dfs(0, 0); dfs(1, 1);cout << "Case #" << cas << ": " << ans << "\n"; cas++;}return 0;
}

HDU - 3068

给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.
回文就是正反读都是一样的字符串,如aba, abba等

Input

输入有多组case,不超过120组,每组输入为一行小写英文字符a,b,c...y,z组成的字符串S
两组case之间由空行隔开(该空行不用处理)
字符串长度len <= 110000

Output

每一行一个整数x,对应一组case,表示该组case的字符串中所包含的最长回文长度.

Sample Input

aaaaabab

Sample Output

4
3
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 200005;
const int N = 26;
long long ans = 0;
struct Palindromic_Tree {int next[MAXN][N];//next指针,next指针和字典树类似,指向的串为当前串两端加上同一个字符构成  int fail[MAXN];//fail指针,失配后跳转到fail指针指向的节点  int cnt[MAXN]; //表示节点i表示的本质不同的串的个数(建树时求出的不是完全的,最后count()函数跑一遍以后才是正确的) int num[MAXN]; //表示以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数int len[MAXN];//len[i]表示节点i表示的回文串的长度(一个节点表示一个回文串)int S[MAXN];//存放添加的字符  int last;//指向新添加一个字母后所形成的最长回文串表示的节点。int n;//表示添加的字符个数。int p;//表示添加的节点个数。int newnode(int l) {//新建节点  for (int i = 0; i < N; ++i) next[p][i] = 0;cnt[p] = 0;num[p] = 0;len[p] = l; ans = max(ans, 1LL * l);return p++;}void init() {//初始化  p = 0;newnode(0);newnode(-1);last = 0;n = 0;S[n] = -1;//开头放一个字符集中没有的字符,减少特判  fail[0] = 1;}int get_fail(int x) {//和KMP一样,失配后找一个尽量最长的  while (S[n - len[x] - 1] != S[n]) x = fail[x];return x;}void add(int c) {c -= 'a';S[++n] = c;int cur = get_fail(last);//通过上一个回文串找这个回文串的匹配位置  if (!next[cur][c]) {//如果这个回文串没有出现过,说明出现了一个新的本质不同的回文串  int now = newnode(len[cur] + 2);//新建节点  fail[now] = next[get_fail(fail[cur])][c];//和AC自动机一样建立fail指针,以便失配后跳转  next[cur][c] = now;num[now] = num[fail[now]] + 1;}last = next[cur][c];cnt[last] ++;}void count() {for (int i = p - 1; i >= 0; --i) cnt[fail[i]] += cnt[i];//父亲累加儿子的cnt,因为如果fail[v]=u,则u一定是v的子回文串!  }
};
Palindromic_Tree pam1;
int main() {ios::sync_with_stdio(0);cin.tie(0); cout.tie(0);string n, m;while(cin>>n){pam1.init(); ans = 1;for (int i = 0; i < n.length(); i++) {pam1.add(n[i]);}cout << ans << "\n";}return 0;
}

HDU - 3948

输出一个字符串不同的回文串的数量

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 200005;
const int N = 26;
long long ans = 0;
struct Palindromic_Tree {int next[MAXN][N];//next指针,next指针和字典树类似,指向的串为当前串两端加上同一个字符构成  int fail[MAXN];//fail指针,失配后跳转到fail指针指向的节点  int cnt[MAXN]; //表示节点i表示的本质不同的串的个数(建树时求出的不是完全的,最后count()函数跑一遍以后才是正确的) int num[MAXN]; //表示以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数int len[MAXN];//len[i]表示节点i表示的回文串的长度(一个节点表示一个回文串)int S[MAXN];//存放添加的字符  int last;//指向新添加一个字母后所形成的最长回文串表示的节点。int n;//表示添加的字符个数。int p;//表示添加的节点个数。int newnode(int l) {//新建节点  for (int i = 0; i < N; ++i) next[p][i] = 0;cnt[p] = 0;num[p] = 0;len[p] = l; ans = max(ans, 1LL * l);return p++;}void init() {//初始化  p = 0;newnode(0);newnode(-1);last = 0;n = 0;S[n] = -1;//开头放一个字符集中没有的字符,减少特判  fail[0] = 1;}int get_fail(int x) {//和KMP一样,失配后找一个尽量最长的  while (S[n - len[x] - 1] != S[n]) x = fail[x];return x;}void add(int c) {c -= 'a';S[++n] = c;int cur = get_fail(last);//通过上一个回文串找这个回文串的匹配位置  if (!next[cur][c]) {//如果这个回文串没有出现过,说明出现了一个新的本质不同的回文串  int now = newnode(len[cur] + 2);//新建节点  fail[now] = next[get_fail(fail[cur])][c];//和AC自动机一样建立fail指针,以便失配后跳转  next[cur][c] = now;num[now] = num[fail[now]] + 1;}last = next[cur][c];cnt[last] ++;}void count() {for (int i = p - 1; i >= 0; --i) cnt[fail[i]] += cnt[i];//父亲累加儿子的cnt,因为如果fail[v]=u,则u一定是v的子回文串!  }
};
Palindromic_Tree pam1;
int main() {ios::sync_with_stdio(0);cin.tie(0); cout.tie(0);string n, m; int cas = 1, te; cin >> te;while(te--){cin >> n;pam1.init(); ans = 1;for (int i = 0; i < n.length(); i++) {pam1.add(n[i]);}pam1.count();cout << "Case #" << cas << ": " << pam1.p - 2 << "\n"; cas++;}return 0;
}

HYSBZ - 2565

顺序和逆序读起来完全一样的串叫做回文串。比如 acbca 是回文串,而 abc 不是( abc 的顺序为 “abc” ,逆序为 “cba” ,不相同)。
输入长度为 n 的串 S ,求 S 的最长双回文子串 T, 即可将 T 分为两部分 X , Y ,( |X|,|Y|≥1 )且 X 和 Y 都是回文串。

求最长双回文子串长度。

对每一个位置而言ans = max(ans ,以此位置为结尾的最长回文串+以i+1为开头的最长回文串)双向分别建一次树就好了。

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 200005;
const int N = 26;
long long ans = 0;
struct Palindromic_Tree {int next[MAXN][N];//next指针,next指针和字典树类似,指向的串为当前串两端加上同一个字符构成  int fail[MAXN];//fail指针,失配后跳转到fail指针指向的节点  int cnt[MAXN]; //表示节点i表示的本质不同的串的个数(建树时求出的不是完全的,最后count()函数跑一遍以后才是正确的) int num[MAXN]; //表示以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数int len[MAXN];//len[i]表示节点i表示的回文串的长度(一个节点表示一个回文串)int S[MAXN];//存放添加的字符  int last;//指向新添加一个字母后所形成的最长回文串表示的节点。int n;//表示添加的字符个数。int p;//表示添加的节点个数。int newnode(int l) {//新建节点  for (int i = 0; i < N; ++i) next[p][i] = 0;cnt[p] = 0;num[p] = 0;len[p] = l; ans = max(ans, 1LL * l);return p++;}void init() {//初始化  p = 0;newnode(0);newnode(-1);last = 0;n = 0;S[n] = -1;//开头放一个字符集中没有的字符,减少特判  fail[0] = 1;}int get_fail(int x) {//和KMP一样,失配后找一个尽量最长的  while (S[n - len[x] - 1] != S[n]) x = fail[x];return x;}void add(int c) {c -= 'a';S[++n] = c;int cur = get_fail(last);//通过上一个回文串找这个回文串的匹配位置  if (!next[cur][c]) {//如果这个回文串没有出现过,说明出现了一个新的本质不同的回文串  int now = newnode(len[cur] + 2);//新建节点  fail[now] = next[get_fail(fail[cur])][c];//和AC自动机一样建立fail指针,以便失配后跳转  next[cur][c] = now;num[now] = num[fail[now]] + 1;}last = next[cur][c];cnt[last] ++;}void count() {for (int i = p - 1; i >= 0; --i) cnt[fail[i]] += cnt[i];//父亲累加儿子的cnt,因为如果fail[v]=u,则u一定是v的子回文串!  }
};
Palindromic_Tree pam1, pam2;
int sum[100010], sum2[100010];
int main() {ios::sync_with_stdio(0);cin.tie(0); cout.tie(0);string n, m; int cas = 1, te;cin >> n;pam1.init(); ans = 1; pam2.init();for (int i = 0; i < n.length(); i++) {pam1.add(n[i]);sum[i] = pam1.len[pam1.last];}for (int i = n.length() - 1; i >= 0; i--) {pam2.add(n[i]);sum2[i] = pam2.len[pam2.last];}int ans = 0;for (int i = 0; i < n.length() - 1; i++) {ans = max(sum[i] + sum2[i + 1], ans);}cout << ans << "\n";return 0;
}

URAL - 1960

对于字符串n,对于i(0-n.length()-1),输出前i个字符能够构成的回文串数量。

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
const int MAXN = 200005;
const int N = 26;
long long ans = 0;
struct Palindromic_Tree {int next[MAXN][N];//next指针,next指针和字典树类似,指向的串为当前串两端加上同一个字符构成  int fail[MAXN];//fail指针,失配后跳转到fail指针指向的节点  int cnt[MAXN]; //表示节点i表示的本质不同的串的个数(建树时求出的不是完全的,最后count()函数跑一遍以后才是正确的) int num[MAXN]; //表示以节点i表示的最长回文串的最右端点为回文串结尾的回文串个数int len[MAXN];//len[i]表示节点i表示的回文串的长度(一个节点表示一个回文串)int S[MAXN];//存放添加的字符  int last;//指向新添加一个字母后所形成的最长回文串表示的节点。int n;//表示添加的字符个数。int p;//表示添加的节点个数。int newnode(int l) {//新建节点  for (int i = 0; i < N; ++i) next[p][i] = 0;cnt[p] = 0;num[p] = 0;len[p] = l; ans = max(ans, 1LL * l);return p++;}void init() {//初始化  p = 0;newnode(0);newnode(-1);last = 0;n = 0;S[n] = -1;//开头放一个字符集中没有的字符,减少特判  fail[0] = 1;}int get_fail(int x) {//和KMP一样,失配后找一个尽量最长的  while (S[n - len[x] - 1] != S[n]) x = fail[x];return x;}void add(int c) {c -= 'a';S[++n] = c;int cur = get_fail(last);//通过上一个回文串找这个回文串的匹配位置  if (!next[cur][c]) {//如果这个回文串没有出现过,说明出现了一个新的本质不同的回文串  int now = newnode(len[cur] + 2);//新建节点  fail[now] = next[get_fail(fail[cur])][c];//和AC自动机一样建立fail指针,以便失配后跳转  next[cur][c] = now;num[now] = num[fail[now]] + 1;}last = next[cur][c];cnt[last] ++;}void count() {for (int i = p - 1; i >= 0; --i) cnt[fail[i]] += cnt[i];//父亲累加儿子的cnt,因为如果fail[v]=u,则u一定是v的子回文串!  }
};
Palindromic_Tree pam1;
int main() {ios::sync_with_stdio(0);cin.tie(0); cout.tie(0);string n, m; int cas = 1, te;cin >> n;pam1.init(); for (int i = 0; i < n.length(); i++) {pam1.add(n[i]);cout << pam1.p - 2; if (i != n.length() - 1)cout << " ";}return 0;
}

反手套一波回文树模板加例题就很舒服相关推荐

  1. 回文树 / 自动机模板

    const int maxn = 400000; const int N = 26 ;struct Palindromic_Tree {int next[maxn][N] ;//next指针,next ...

  2. 回文树(模板)+ 例题

    引用: Palindromic Tree--回文树[处理一类回文串问题的强力工具] 回文树练习题集 首先,回文树有何功能? 假设我们有一个串S,S下标从0开始,则回文树能做到如下几点: 1.求串S前缀 ...

  3. 2014-2015 ACM-ICPC, Asia Xian Regional Contest G The Problem to Slow Down You 回文树

    The Problem to Slow Down You Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hust.edu.cn/vjud ...

  4. 回文树(回文自动机) - URAL 1960 Palindromes and Super Abilities

     Palindromes and Super Abilities Problem's Link:  http://acm.timus.ru/problem.aspx?space=1&num=1 ...

  5. 回文树笔记(转自quack_quack)

    1.回文树的next[charset]指针: b->aba 那么就这样表示:b.next[a]=aba 当然树里面肯定不能存字符串,于是就直接用下标标号代替了 2.回文树的fail指针: 跟ac ...

  6. 「学习笔记」回文树/回文自动机(Palindromic Tree)

    引入 有时候题目要求一些这样的问题 1. 求以串 s s s 本质不同的回文串个数(即长度不同或长度相同且至少有一个字符不相同的字符串) 2. 求以位置i" role="prese ...

  7. 回文树/回文自动机学习

    len[i]:节点i的回文串的长度 next[i][c]:节点i的回文串在两边添加字符c以后变成的回文串的编号 fail[i]:指向i的最长回文后缀且不为i cnt[i]:节点i表示的回文串在S中出现 ...

  8. 回文自动机 / 回文树

    B站讲解视频 B站视频对于pre数组(fail数组)的讲解较清晰,可供参考. 参考博客 模板 #include <queue> #include <cstdlib> #incl ...

  9. 2018 ICPC 南京 M. Mediocre String Problem(ExKMP + Manacher / ExKMP+回文树)

    2018 ICPC 南京 全文见:https://blog.csdn.net/qq_43461168/article/details/112796538 M. Mediocre String Prob ...

最新文章

  1. 张量的通俗理解和计算
  2. zblog php版调用代码,zblogphp调用指定单篇文章代码升级版
  3. 小波变换和motion信号处理(二)【转载】
  4. 重磅!深度学习的顶级会议ICLR 2020 数据图文详解
  5. mysql like html_mysql - MySQL RLIKE查找,然后替换打开和关闭HTML标记之间的所有字符 - 堆栈内存溢出...
  6. iPhone X 再曝新 Bug:电话无法接听!
  7. html中el表达式遍历list,使用EL表达式访问集合
  8. 如何用atom编辑python_对于新手来说 如何用atom搭建python的ide?
  9. 教程 | 做一个自己专属的本地 BLAST 数据库
  10. 从虚拟偶像到“网红”VUP,变现狂欢下的浮士德交易
  11. Codeforces 686 D - Kay and Snowflake
  12. Java 生成视频缩略图(ffmpeg)
  13. 未来的计算机能帮人类炒股,未来计算机能帮人类炒股吗
  14. leaflet 设置地图上某个标注位于页面最上层
  15. 初学者の发送QQ邮箱完整代码
  16. 微信小程序●云开发部署攻略
  17. 华为机试--简单题(一)
  18. 梦幻西游109散人最多的服务器,老鸡解读真实的梦幻 最高在线保守80W!
  19. 计算机体系架构(5)总线与 IO 接口
  20. ThinkPad T460S 拆解图 拆解图

热门文章

  1. Ubuntu16.04下实现darknet-yolov3训练自己的数据(含loss图、mAP计算)
  2. SOM-TL138Linux SD系统启动卡制作方法
  3. 软路由(openwrt)的三个基础知识
  4. 如果你比较注重数据隐私,这7个硬盘销毁的方法,请一定记住!
  5. FFF Network助力区块链应用创新与落地
  6. 是否有每10分钟发出一次提醒的便签APP?
  7. 315MHz 遥控器固定码信号分析和重放
  8. 运行时内存-CPU多级缓存
  9. Windows下安装NTP服务器
  10. 张家俊:ChatGPT八个技术问题的猜想