字符串
Trie
简介
将
例题
P8306【模板】字典树
分析
字典树模板,建个字典树然后查询,注意要把数字和字母转换为数字下标。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
inline void write(int x){if (x < 0) putchar('-'), x = -x;if (x > 9) write(x / 10);putchar(x % 10 + '0');}
const int N = 3e6 + 10;
int T, n, q;
char c[N];
int trie[N][65], tot, cnt[N];
int get(char c){
if (c >= 'a' && c <= 'z') return c - 'a';
if (c >= 'A' && c <= 'Z') return c - 'A' + 26;
if (c >= '0' && c <= '9') return c - '0' + 52;
}
void insert(char *c){
int sz = strlen(c + 1), now = 0;
for (int i = 1; i <= sz; i++){
int &to = trie[now][get(c[i])];
if (!to) to = ++tot;
now = to;
cnt[now]++;
}
}
int find(char *c){
int sz = strlen(c + 1), now = 0;
for (int i = 1; i <= sz; i++){
int to = trie[now][get(c[i])];
if (!to) return 0;
now = to;
}
return cnt[now];
}
int main(){
T = read();
while (T--){
for (int i = 0; i <= tot; i++){
for (int j = 0; j < 62; j++){
trie[i][j] = 0;
}
cnt[i] = 0;
}
tot = 0;
n = read(), q = read();
for (int i = 1; i <= n; i++){
cin >> c + 1;
insert(c);
}
for (int i = 1; i <= q; i++){
cin >> c + 1;
printf("%d\n", find(c));
}
}
return 0;
}
P4471 [BJWC2018]词韵
分析
显然易见,我们可以反着建一遍边,则题目转换为最长公共前缀,即可发现,两个字符串的结尾处,要么是兄弟,要么是父子关系,然后考虑树形
对于每一个点,我们设
继续考虑,我们发现
最后考虑答案统计,肯定是由一个最长链和一个次长链与剩余儿子个数加上自己。
代码
#include<iostream>
#include<cstring>
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
inline void write(int x){if (x < 0) putchar('-'), x = -x;if (x > 9) write(x / 10);putchar(x % 10 + '0');}
const int N = 3e6 + 10;
int n, ans;
char c[N];
int trie[N][27], tot;
bool word[N];
int f[N];
void insert(char *c){
int sz = strlen(c + 1), now = 0;
for (int i = sz; i >= 1; i--){
int &to = trie[now][c[i] - 'a'];
if (!to) to = ++tot;
now = to;
}
word[now] = 1;
}
void dfs(int u){
int maxx = 0, maxn = 0, child = 0;
for (int i = 0; i < 26; i++){
int v = trie[u][i];
if (!v) continue;
child += word[v];
dfs(v);
if (f[v] > maxx) maxn = maxx, maxx = f[v];
else maxn = max(maxn, f[v]);
}
ans = max(ans, maxx + maxn + word[u] + max(0, child - 2));
if (!word[u]){
f[u] = 0;
return;
}
f[u] = maxx + word[u] + max(0, child - 1);
}
int main(){
n = read();
for (int i = 1; i <= n; i++){
cin >> c + 1;
insert(c);
}
dfs(0);
printf("%d\n", ans);
return 0;
}
P4551 最长异或路径
分析
可以考虑将每个点到根节点的异或值求出来(默认根节点为
代码
#include<iostream>
#include<cstdio>
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
inline void write(int x){if (x < 0) putchar('-'), x = -x;if (x > 9) write(x / 10);putchar(x % 10 + '0');}
const int N = 1e5 + 10, M = 3e6 + 10;
int n, ans;
struct tree{
int v, w, nxt;
}t[N << 1];
int head[N], cnt;
void add(int u, int v, int w){
t[++cnt] = (tree){v, w, head[u]};
head[u] = cnt;
}
int sum[N];
void dfs(int u, int fa){
for (int i = head[u]; i; i = t[i].nxt){
int v = t[i].v;
if (v == fa) continue;
sum[v] = sum[u] ^ t[i].w;
dfs(v, u);
}
}
int trie[M][2], tot;
void insert(int s){
int now = 0;
for (int i = 1 << 30; i; i >>= 1){
bool v = s & i;
int &to = trie[now][v];
if (!to) to = ++tot;
now = to;
}
}
int find(int s){
int sum = 0, now = 0;
for (int i = 1 << 30; i; i >>= 1){
bool v = s & i;
int to = trie[now][!v];
if (to) sum += i, now = to;
else now = trie[now][v];
}
return sum;
}
int main(){
n = read();
for (int i = 1; i < n; i++){
int u = read(), v = read(), w = read();
add(u, v, w);
add(v, u, w);
}
dfs(1, 0);
for (int i = 1; i <= n; i++){
insert(sum[i]);
}
for (int i = 1; i <= n; i++){
ans = max(ans, find(sum[i]));
}
printf("%d\n", ans);
return 0;
}
KMP
AC自动机
简介
多字符串匹配的算法。
例题
P3808 【模板】AC 自动机(简单版)
代码
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
inline void write(int x){if (x < 0) putchar('-'), x = -x;if (x > 9) write(x / 10);putchar(x % 10 + '0');}
const int N = 1e6 + 10;
int n;
char s[N];
namespace AC{
int trie[N][27], word[N], tot;
void insert(char *c){
int sz = strlen(c + 1), now = 0;
for (int i = 1; i <= sz; i++){
int &to = trie[now][c[i] - 'a'];
if (!to) to = ++tot;
now = to;
}
word[now]++;
}
int fail[N];
queue<int> q;
void build(){
for (int i = 0; i < 26; i++){
if (trie[0][i]) q.push(trie[0][i]);
}
while (!q.empty()){
int u = q.front();q.pop();
for (int i = 0; i < 26; i++){
if (trie[u][i]) fail[trie[u][i]] = trie[fail[u]][i], q.push(trie[u][i]);
else trie[u][i] = trie[fail[u]][i];
}
}
}
int query(char *t){
int sz = strlen(t + 1), now = 0, sum = 0;
for (int i = 1; i <= sz; i++){
int to = trie[now][t[i] - 'a'];
for (int j = to; j && word[j] != -1; j = fail[j]){
sum += word[j], word[j] = -1;
}
now = to;
}
return sum;
}
}using namespace AC;
int main(){
n = read();
for (int i = 1; i <= n; i++){
cin >> s + 1;
insert(s);
}
cin >> s + 1;
build();
printf("%d\n", query(s));
return 0;
}
P3796 【模板】AC 自动机(加强版)
代码
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
inline void write(int x){if (x < 0) putchar('-'), x = -x;if (x > 9) write(x / 10);putchar(x % 10 + '0');}
const int N = 160, SZ = N * 80, M = 1e6 + 10, P = 80;
int n;
char s[N][P], t[M];
namespace AC{
int trie[SZ][27], idx[SZ], tot;
void insert(char *c, int id){
int sz = strlen(c + 1), now = 0;
for (int i = 1; i <= sz; i++){
int &to = trie[now][c[i] - 'a'];
if (!to) to = ++tot;
now = to;
}
idx[now] = id;
}
int fail[SZ];
queue<int> q;
void build(){
for (int i = 0; i < 26; i++){
if (trie[0][i]) q.push(trie[0][i]);
}
while (!q.empty()){
int u = q.front();q.pop();
for (int i = 0; i < 26; i++){
if (trie[u][i]) fail[trie[u][i]] = trie[fail[u]][i], q.push(trie[u][i]);
else trie[u][i] = trie[fail[u]][i];
}
}
}
int val[SZ], cnt[SZ];
int query(char *t){
int sz = strlen(t + 1), now = 0, sum = 0;
for (int i = 1; i <= sz; i++){
int to = trie[now][t[i] - 'a'];
for (int j = to; j; j = fail[j]) val[j]++;
now = to;
}
for (int i = 0; i <= tot; i++){
if (idx[i]) sum = max(sum, val[i]), cnt[idx[i]] = val[i];
}
return sum;
}
void init(){
memset(trie, 0, sizeof trie);
memset(idx, 0, sizeof idx);
memset(fail, 0, sizeof fail);
while (!q.empty()) q.pop();
memset(val, 0, sizeof val);
memset(cnt, 0, sizeof cnt);
tot = 0;
}
}using namespace AC;
int main(){
while (~scanf("%d", &n)){
init();
if (!n) break;
for (int i = 1; i <= n; i++){
cin >> s[i] + 1;
insert(s[i], i);
}
cin >> t + 1;
build();
int ans = query(t);
printf("%d\n", ans);
for (int i = 1; i <= n; i++){
if (cnt[i] == ans) printf("%s\n", s[i] + 1);
}
}
return 0;
}
P5357 【模板】AC 自动机(二次加强版)
代码
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
inline int read(){register int x = 0, f = 1;register char c = getchar();while (c < '0' || c > '9'){if (c == '-') f = -1;c = getchar();}while (c >= '0' && c <= '9'){x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return x * f;}
inline void write(int x){if (x < 0) putchar('-'), x = -x;if (x > 9) write(x / 10);putchar(x % 10 + '0');}
const int N = 2e5 + 10, M = 2e6 + 10;
int n;
char s[N], t[M];
namespace AC{
struct edge{
int v, nxt;
}e[N];
int head[N], cnt;
void add(int u, int v){
e[++cnt] = (edge){v, head[u]};
head[u] = cnt;
}
int trie[N][27], idx[N], tot;
void insert(char *c, int id){
int sz = strlen(c + 1), now = 0;
for (int i = 1; i <= sz; i++){
int &to = trie[now][c[i] - 'a'];
if (!to) to = ++tot;
now = to;
}
idx[id] = now;
}
int fail[N];
queue<int> q;
void build(){
for (int i = 0; i < 26; i++){
if (trie[0][i]) q.push(trie[0][i]);
}
while (!q.empty()){
int u = q.front();q.pop();
for (int i = 0; i < 26; i++){
if (trie[u][i]) fail[trie[u][i]] = trie[fail[u]][i], q.push(trie[u][i]);
else trie[u][i] = trie[fail[u]][i];
}
}
for (int i = 1; i <= tot; i++){
add(fail[i], i);
}
}
int val[N];
void query(char *t){
int sz = strlen(t + 1), now = 0;
for (int i = 1; i <= sz; i++){
int to = trie[now][t[i] - 'a'];
val[to]++;
now = to;
}
}
int ans[N];
void dfs(int u){
ans[u] = val[u];
for (int i = head[u]; i; i = e[i].nxt){
int v = e[i].v;
dfs(v);
ans[u] += ans[v];
}
}
}using namespace AC;
int main(){
n = read();
for (int i = 1; i <= n; i++){
cin >> s + 1;
insert(s, i);
}
cin >> t + 1;
build();
query(t);
dfs(0);
for (int i = 1; i <= n; i++){
printf("%d\n", ans[idx[i]]);
}
return 0;
}
本文作者:bryce_yyds
本文链接:https://www.cnblogs.com/bryceyyds/p/17075852.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步