P9437 『XYGOI round1』一棵树 (换根dp)
trick+换根dp
对于此类 「将数字顺次写下」 计算贡献的题目,通常按位考虑,并且考虑每个数作为 开头/结尾 时的贡献,方便计算。
因此,我们在这题中考虑每个数作为结尾时的贡献。那么这题就转化成:计算以
首先考虑处理出各个子树中的贡献,设
其中
考虑如何换根,也就是计算
答案
#include <bits/stdc++.h>
#define pii std::pair<int, int>
#define fi first
#define se second
#define pb push_back
typedef long long i64;
const i64 iinf = 0x3f3f3f3f, linf = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10, mod = 998244353;
int n;
i64 ans, c[N], f[N], sz[N], b[N], a[N];
std::vector<int> e[N];
void dfs1(int u, int fa) {
sz[u] = 1, f[u] = a[u];
for(auto v : e[u]) {
if(v == fa) continue;
dfs1(v, u);
f[u] = (f[u] + f[v] * b[u] % mod + sz[v] * a[u] % mod) % mod;
sz[u] += sz[v];
}
}
void dfs2(int u, int fa) {
ans = (ans + f[u]) % mod;
for(auto v : e[u]) {
if(v == fa) continue;
f[v] = (f[v] + (f[u] - f[v] * b[u] % mod + mod - sz[v] * a[u] % mod + mod) * b[v] % mod + (sz[1] - sz[v]) * a[v] % mod) % mod;
dfs2(v, u);
}
}
void Solve() {
std::cin >> n;
c[1] = 10;
for(int i = 2; i <= 9; i++) c[i] = c[i - 1] * 10;
for(int i = 1; i <= n; i++) {
std::cin >> a[i];
if(!a[i]) b[i] = 10;
else {
int cnt = 0;
i64 now = a[i];
while(now) {
now /= 10;
cnt++;
}
b[i] = c[cnt];
}
}
for(int i = 2; i <= n; i++) {
int x;
std::cin >> x;
e[x].pb(i), e[i].pb(x);
}
dfs1(1, 0);
dfs2(1, 0);
std::cout << ans << "\n";
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
Solve();
return 0;
}
标签:
DP
Buy me a cup of coffee ☕.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具