题解 P9437『XYGOI round1』一棵树

换根 DP。

本蒟蒻最初没想到换根,把自己写自闭了...

定义 \(f_u\) 为子树 \(u\) 中的每个结点走到 \(u\) 的贡献和,\(l_u\) 为大于 \(a_u\) 的最小的 \(10\) 的幂次方数,\(sum_u\)\(\sum\limits_{v\in son(u)}{f_v}\)

转移方程为:\(f_u=l_u\cdot\sum\limits_{v\in son(u)}{f_v}+siz_u\cdot a_u\)

再定义 \(g_u\) 为除去子树 \(u\) 其他的所有点到 \(fa_u\) 的贡献和。

转移方程为:\(g_v=(g_u+sum_u-f_v)\cdot l_u+(n-siz_v)\cdot a_u\)

然后答案加上 \((g_v+sum_v)\cdot l_v+n\cdot a_v\)

复杂度 \(O(n)\)

code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5,mod=998244353;
ll n,a[N],f[N],g[N],siz[N],sum[N],ans;
vector<int>adj[N];
ll get(ll x){
	if(x==0)return 10;
	ll res=1;
	while(x){res*=10;x/=10;}
	return res;
}
void dfs(int u,int lst){
	siz[u]=1;
	ll t=get(a[u]);f[u]=a[u];
	for(int i=0;i<adj[u].size();++i){
		int v=adj[u][i];if(v==lst)continue;
		dfs(v,u);siz[u]+=siz[v];f[u]=(f[u]+f[v]*t+siz[v]*a[u])%mod;sum[u]=(sum[u]+f[v])%mod;
	}
}
void dfs2(int u,int lst){
	ll tu=get(a[u]);
	for(int i=0;i<adj[u].size();++i){
		ll v=adj[u][i],tv=get(a[v]);if(v==lst)continue;
		g[v]=(g[u]+(sum[u]-f[v]+mod)%mod)%mod*tu+(n-siz[v])*a[u];g[v]%=mod;
		ans=(ans+(g[v]+sum[v])*tv+n*a[v])%mod;
		dfs2(v,u);
	}
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	cin>>n;for(int i=1;i<=n;++i)cin>>a[i];
	for(int u=2;u<=n;++u){
		int v;cin>>v;
		adj[u].push_back(v);adj[v].push_back(u);
	}
	dfs(1,0);ans+=f[1];dfs2(1,0);
	cout<<ans<<endl;
	return 0;
}
posted @ 2023-07-17 23:02  HQJ2007  阅读(25)  评论(0)    收藏  举报