给定一组字符串s1,s2,⋯,sn,任选k 个sa1,sa2,⋯,sak(ai=aj),最小化1⩽i,j⩽k,i=jmaxlcp(sai,saj)。其中lcp(p,q) 是字符串p 和字符串q 的最长公共前缀,字符串的大小即为其字典序的大小。数据范围:2⩽k⩽n⩽106 且∑∣si∣≤106。(2023GDCPC E. New but Nostalgic Problem)
#include<iostream> #include<cstring> #include<algorithm> constexprint N = 5e6 + 8; using ll = longlong; usingnamespace std;
structTrie { staticconstexprchar base = 'a'; staticconstexprint tot = 26; int pcnt; // 总节点数 int vis[N]; // 是否访问过 int dep[N]; // 字典树深度 int ecnt[N]; // 以该节点为末字符的字符串数量 int icnt[N]; // 经过该节点的字符串数量 int nxt[N][tot]; // 存的是子树编号
#include<iostream> #include<cstring> #include<algorithm> constexprint N = 5e5 + 8; using ll = longlong; usingnamespace std;
structTrie { staticconstexprchar base = 'a'; staticconstexprint tot = 26; int pcnt; // 总节点数 int vis[N]; // 是否访问过 int dep[N]; // 字典树深度 int ecnt[N]; // 以该节点为末字符的字符串数量 int icnt[N]; // 经过该节点的字符串数量 int nxt[N][tot]; // 存的是子树编号
voidinsert(const string& s, int p = 1){ ++icnt[p]; for (int i = 0; i < s.size(); ++i) { char c = s[i] - base; if (!nxt[p][c]) nxt[p][c] = ++pcnt, init(pcnt); p = nxt[p][c]; ++icnt[p]; // 经过该节点的字符串数量 dep[p] = i + 1; } ++ecnt[p]; // 以该节点为末字符的字符串数量 }
intfind(const string& s, int p = 1){ for (int i = 0; i < s.size(); ++i) { char c = s[i] - base; if (!nxt[p][c]) return0; p = nxt[p][c]; } return p; } } T[2];
int f[5008][2]; // 前i个字符最少数量 voideachT(){ int n; string s;
#include<iostream> #include<cstring> #include<algorithm> constexprint N = 5e6 + 8; using ll = longlong; usingnamespace std;
structTrie { staticconstexprchar base = 'a'; staticconstexprint tot = 26; int pcnt; // 总节点数 int vis[N]; // 是否访问过 int dep[N]; // 字典树深度 int ecnt[N]; // 以该节点为末字符的字符串数量 int icnt[N]; // 经过该节点的字符串数量 int nxt[N][tot]; // 存的是子树编号
voidinsert(const string& s, int p = 1){ ++icnt[p]; for (int i = 0; i < s.size(); ++i) { char c = s[i] - base; if (!nxt[p][c]) nxt[p][c] = ++pcnt, init(pcnt); p = nxt[p][c]; ++icnt[p]; // 经过该节点的字符串数量 dep[p] = i + 1; } ++ecnt[p]; // 以该节点为末字符的字符串数量 }
intfind(const string& s, int p = 1){ for (int i = 0; i < s.size(); ++i) { char c = s[i] - base; if (!nxt[p][c]) return0; p = nxt[p][c]; } return p; }
// 公共前缀 intfindcp(const string& s){ int p = 1; ll sum = 0; for (auto& c : s) { sum += ecnt[p]; if (!nxt[p][c - 48]) return sum; p = nxt[p][c - 48]; } return sum += icnt[p]; } } T;
voideachT(){ int n, q; cin >> n >> q;
T.init();
while (n--) { string s; int m; cin >> m; while (m--) { int x; cin >> x; s += (char)(x + '0'); } T.insert(s); // 插入 }
while (q--) { string s; int m; cin >> m; while (m--) { int x; cin >> x; s += (char)(x + '0'); } printf("%d\n", T.findcp(s)); } }
constexprint N = 2e6 + 8, tot = 27; constexprchar base = 'a' - 1;
int nxt[N][tot]; int pcnt; int cnt[N][tot]; ll dp[tot][tot];
voidinsert(const string& s, int p = 1){ for (auto C : s) { int c = C - base; if (!nxt[p][c]) nxt[p][c] = ++pcnt; for (int i = 0; i < tot; ++i) { if (i == c) continue; dp[c][i] += cnt[p][i]; } cnt[p][c] += 1; p = nxt[p][c]; } }
voideachT(){ int n, q; cin >> n >> q;
pcnt = 1;
for (int i = 0; i < n; ++i) { string s; cin >> s; s = s + base; insert(s); }
while (q--) { string s; cin >> s; s = base + s; ll ans = 0; for (int l = 0; l < tot; ++l) { for (int r = l + 1; r < tot; ++r) { ans += dp[s[l] - base][s[r] - base]; } } cout << ans << '\n'; } }
voidinsert(const ll x, int p = 1){ for (int bit = 0; bit <= D; ++bit) { bool c = x & (1ll << bit); if (!t[p][c]) t[p][c] = ++pcnt, init(pcnt); p = t[p][c]; dep[p] = bit + 1; } ++ecnt[p]; }
#include<iostream> #include<algorithm> constexprint N = 3e6 + 8; usingnamespace std;
constexprchar base = 'a'; constexprint tot = 26; int pcnt; // 总节点数 int ecnt[N]; // 以该节点为末字符的字符串数量 int nxt[N][tot]; // 存的是子树编号
voidinsert(const string& s, int p = 1){ for (auto& c : s) { if (!nxt[p][c - base]) nxt[p][c - base] = ++pcnt; p = nxt[p][c - base]; } ++ecnt[p]; // 以该节点为末字符的字符串数量 }
int d, dp1[N], dp2[N]; // 直径 最长链 次长链 voiddfs(int p){ int cnt = 0; // 子节点数量 for (int i = 0; i < tot; ++i) { int& v = nxt[p][i]; if (!v) continue; dfs(v);
#include<iostream> #include<algorithm> constexprint N = 2e5 + 8; usingnamespace std;
string s;
intch(char c){ if (c == 'A') return0; if (c == 'C') return1; if (c == 'T') return2; if (c == 'G') return3; return-1; }
constexprint tot = 4; int pcnt = 0; int nxt[N][tot]; int ecnt[N]; voidinsert(const string& s, int p = 1){ for (auto& c : s) { if (!nxt[p][ch(c)]) nxt[p][ch(c)] = ++pcnt; p = nxt[p][ch(c)]; } ++ecnt[p]; }
int ans = 0; bool vis[N][508]; voiddfs(int p, int si){ if (vis[p][si]) return; vis[p][si] = 1;
if (si == s.size()) { ans += ecnt[p]; return; }
if (s[si] == '*') { dfs(p, si + 1); for (int i = 0; i <= 3; ++i) { if (nxt[p][i]) dfs(nxt[p][i], si); } } elseif (s[si] == '?') { for (int i = 0; i <= 3; ++i) { if (nxt[p][i]) dfs(nxt[p][i], si + 1); } } else { int i = ch(s[si]); if (nxt[p][i]) dfs(nxt[p][i], si + 1); } }
intmain(){ pcnt = 1;
cin >> s;
int n; cin >> n; for (int i = 1; i <= n; ++i) { string t; cin >> t; insert(t); }
#include<bits/stdc++.h> using ll = longlong; usingnamespace std;
structTrie { staticconstexprint N = 2e6 + 8; staticconstexprchar base = 'a'; staticconstexprint tot = 26; int pcnt; // 总节点数 int vis[N]; // 是否访问过 int dep[N]; // 字典树深度 int ecnt[N]; // 以该节点为末字符的字符串数量 int icnt[N]; // 经过该节点的字符串数量 int nxt[N][tot]; // 存的是子树编号
voidinsert(const string& s, int p = 0){ icnt[p]++; for (int i = 0; i < s.size(); ++i) { char c = s[i] - base; if (!nxt[p][c]) init(nxt[p][c] = pcnt++); p = nxt[p][c]; icnt[p]++; // 经过该节点的字符串数量 dep[p] = i; } ecnt[p]++; } } T;
intmain(){ int n; cin >> n;
T.init();
ll res = 0; vector<string> s(n); for (int i = 0; i < n; i++) { cin >> s[i]; T.insert(s[i]); res += 1LL * s[i].size() * 2 * n; } for (int i = 1; i < T.pcnt; ++i) { res += 1LL * T.icnt[i] * T.icnt[i]; }
T.init(); for (int i = 0; i < n; i++) { T.insert(s[i]); reverse(s[i].begin(), s[i].end()); T.insert(s[i]); } for (int i = 1; i < T.pcnt; ++i) { res -= 1LL * T.icnt[i] * T.icnt[i]; }
T.init(); for (int i = 0; i < n; i++) { T.insert(s[i]); } for (int i = 1; i < T.pcnt; ++i) { // 这里 [1, pcnt) res += 1LL * T.icnt[i] * T.icnt[i]; }