P4075 [SDOI2016] 模式字符串 题解
考虑点分治。
路径的合并,只需要求出每个点到当前重心的字符串是否可以成为模式串依次相连的前缀或后缀即可。
这显然可以哈希维护,手推一下就知道咋做了。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
using namespace std;
using ull = unsigned long long;
const int N = 1e6 + 5;
const ull BASE = 27, MOD = 1610612741;
int t, n, m;
ull hashing[N];
ull repeat_hash[N];
ull powe[N];
long long ans = 0LL;
string s;
bool del[N];
vector<int> G[N];
int sz[N], tot, wc;
void get_sz(int u, int f)
{
sz[u] = 0;
if (del[u]) return;
sz[u] = 1;
for (auto& j : G[u])
{
if (j ^ f)
{
get_sz(j, u);
sz[u] += sz[j];
}
}
}
void get_wc(int u, int f)
{
if (del[u]) return;
int maxn = tot - sz[u];
for (auto& j : G[u])
{
if (j ^ f)
{
get_wc(j, u);
maxn = max(maxn, sz[j]);
}
}
if (maxn <= (tot >> 1)) wc = u;
}
long long sufcnt[N], precnt[N];
ull nhash[N], revhash[N], rev_repeat_hash[N];
int cur;
char cc[N];
bool canbesuf[N], canbepre[N];
int dist[N];
vector<int> total;
ull subhash(ull* h, int l, int r)
{
return h[r] - h[l - 1] * powe[r - l + 1];
}
void dfs_suf(int u, int f, int w)
{
dist[u] = 0;
cur++;
canbesuf[u] = 0;
if (del[u]) return;
dist[u] = w;
total.emplace_back(u);
nhash[cur] = nhash[cur - 1] * BASE + (ull)(cc[u] - 'A' + 1);
// 判断能否成为后缀
int len = w;
int ls = len / m;
if (ls == 0 || subhash(nhash, len % m + 1, cur) == repeat_hash[ls])
{
if (len % m == 0 || subhash(nhash, 1, len % m) == subhash(hashing, m - len % m + 1, m))
{
canbesuf[u] = 1;
//sufcnt[w]++;
}
}
for (auto& j : G[u])
{
if (j ^ f)
{
dfs_suf(j, u, w + 1);
cur--;
}
}
}
void dfs_pre(int u, int f)
{
cur++;
if (del[u]) return;
nhash[cur] = nhash[cur - 1] * BASE + (ull)(cc[u] - 'A' + 1);
canbepre[u] = 0;
// 判断能否成为后缀
int len = cur;
int ls = len / m;
if (ls == 0 || subhash(nhash, len % m + 1, cur) == rev_repeat_hash[ls])
{
if (len % m == 0 || subhash(nhash, 1, len % m) == subhash(revhash, m - len % m + 1, m))
{
canbepre[u] = 1;
//precnt[cur]++;
}
}
for (auto& j : G[u])
{
if (j ^ f)
{
dfs_pre(j, u);
cur--;
}
}
}
void solve(int u)
{
if (del[u]) return;
cur = 0;
get_sz(u, 0);
tot = sz[u];
wc = u;
get_wc(u, 0);
u = wc;
del[u] = 1;
vector<vector<int>> ntot;
for (auto& j : G[u])
{
total.clear();
total.shrink_to_fit();
cur = 0;
dfs_pre(j, u);
cur = 1;
nhash[cur] = (ull)(cc[u] - 'A' + 1);
dfs_suf(j, u, 2);
for (auto& k : total)
{
if (canbesuf[k])
{
if (dist[k] % m == 0)
{
ans++;
}
ans += precnt[(m - dist[k] % m) % m];
}
if (canbepre[k])
{
if (dist[k] % m == 0 && cc[u] == s[1])
{
ans++;
}
ans += sufcnt[(m - (dist[k] - 1) % m) % m];
}
}
for (auto& k : total)
{
if (canbesuf[k]) sufcnt[dist[k] % m]++;
if (canbepre[k]) precnt[(dist[k] - 1) % m]++;
}
ntot.emplace_back(total);
}
for (auto& j : ntot)
{
for (auto& k : j)
{
canbepre[k] = canbesuf[k] = 0;
sufcnt[dist[k] % m] = precnt[(dist[k] - 1) % m] = 0;
dist[k] = 0;
}
}
for (auto& j : G[u]) solve(j);
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0);
powe[0] = 1;
for (int i = 1; i < N; i++) powe[i] = powe[i - 1] * BASE;
cin >> t;
while (t--)
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >> cc[i];
G[i].clear(), G[i].shrink_to_fit();
del[i] = 0;
}
for (int i = 1; i < n; i++)
{
int u, v;
cin >> u >> v;
G[u].emplace_back(v);
G[v].emplace_back(u);
}
cin >> s;
s = " " + s;
for (int i = 1; i <= m; i++)
{
hashing[i] = hashing[i - 1] * BASE + (ull)(s[i] - 'A' + 1);
}
repeat_hash[1] = hashing[m];
for (int i = 2; 1LL * i * m <= n; i++)
{
repeat_hash[i] = repeat_hash[i - 1] * powe[m] + hashing[m];
}
s.erase(s.begin());
reverse(s.begin(), s.end());
s = " " + s;
for (int i = 1; i <= m; i++) revhash[i] = revhash[i - 1] * BASE + (ull)(s[i] - 'A' + 1);
rev_repeat_hash[1] = revhash[m];
for (int i = 2; 1LL * i * m <= n; i++)
{
rev_repeat_hash[i] = rev_repeat_hash[i - 1] * powe[m] + revhash[m];
}
ans = 0LL;
solve(1);
cout << ans << "\n";
}
return 0;
}
/*
1
9 2
ABAABCBCD
1 2
2 3
3 4
4 5
3 6
6 7
3 8
8 9
AB
*/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现