题解 sign

传送门

发现如果底数是固定的,那么转移是容易的
发现不同的底数只有根号种,所以好像可以 O(nn)
发现需要一个快速幂,所以实际上是 O(nnlogn)
发现精细实现的话可以过
发现其实可以用光速幂优化到 O((n+V)n)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define pb push_back
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n;
int fa[N], a[N];
vector<int> to[N];
const ll mod=998244353;
inline ll qpow(ll a, ll b) {ll ans=1; for (; b; a=a*a%mod,b>>=1) if (b&1) ans=ans*a%mod; return ans;}

// namespace force{
// 	ll f[N], ans[N], base, inv;
// 	void dfs(int u) {
// 		f[u]=1;
// 		for (auto v:to[u]) dfs(v), f[u]=f[u]*f[v]%mod;
// 		if (base==1) f[u]=f[u]*(a[u]+1)%mod;
// 		else f[u]=f[u]*(qpow(base, a[u]+1)-1)%mod*inv%mod;
// 	}
// 	void solve() {
// 		for (int i=1; i<=n; ++i) {
// 			// cout<<"i: "<<i<<endl;
// 			base=to[i].size();
// 			// cout<<"base: "<<base<<endl;
// 			inv=qpow(base-1, mod-2);
// 			dfs(1);
// 			ans[i]=f[i];
// 			// cout<<"f: "; for (int j=1; j<=n; ++j) cout<<f[j]<<' '; cout<<endl;
// 		}
// 		for (int i=1; i<=n; ++i) printf("%lld\n", (ans[i]%mod+mod)%mod);
// 	}
// }

// namespace task1{
// 	bool vis[N];
// 	int tem[N], sqr, tot;
// 	vector<int> buc[N], sta;
// 	ll f[N], ans[N], base, inv;
// 	void dfs(int u) {
// 		tem[++tot]=u;
// 		for (auto v:to[u]) dfs(v);
// 	}
// 	void solve() {
// 		sqr=sqrt(n);
// 		dfs(1);
// 		for (int i=1; i<=n; ++i)
// 			if (to[i].size()<=sqr) buc[to[i].size()].pb(i);
// 			else sta.pb(i);
// 		for (int i=0; i<=sqr; ++i) if (buc[i].size()) {
// 			base=i; inv=qpow(base-1, mod-2);
// 			for (auto it:buc[i]) vis[it]=1;
// 			int cnt=buc[i].size();
// 			for (int j=tot,u; j; --j) {
// 				u=tem[j];
// 				f[u]=1;
// 				for (auto& v:to[u]) f[u]=f[u]*f[v]%mod;
// 				if (base==1) f[u]=f[u]*(a[u]+1)%mod;
// 				else f[u]=f[u]*(qpow(base, a[u]+1)-1)%mod*inv%mod;
// 				if (vis[u]) {
// 					ans[u]=f[u];
// 					if (--cnt==0) break;
// 				}
// 			}
// 			for (auto it:buc[i]) vis[it]=0;
// 		}
// 		for (auto it:sta) {
// 			base=to[it].size(); inv=qpow(base-1, mod-2);
// 			for (int j=tot,u; j; --j) {
// 				u=tem[j];
// 				f[u]=1;
// 				for (auto& v:to[u]) f[u]=f[u]*f[v]%mod;
// 				if (base==1) f[u]=f[u]*(a[u]+1)%mod;
// 				else f[u]=f[u]*(qpow(base, a[u]+1)-1)%mod*inv%mod;
// 				if (u==it) {ans[u]=f[u]; break;}
// 			}
// 		}
// 		for (int i=1; i<=n; ++i) printf("%lld\n", (ans[i]%mod+mod)%mod);
// 	}
// }

namespace task2{
	bool vis[N], npri[N];
	int pri[N], pcnt;
	int tem[N], sqr, tot;
	vector<int> buc[N], sta;
	ll f[N], ans[N], rec[325][N], base, inv;
	void dfs(int u) {
		tem[++tot]=u;
		for (auto v:to[u]) dfs(v);
	}
	void solve() {
		sqr=sqrt(n);
		dfs(1);
		// cout<<double(sizeof(rec))/1000/1000<<endl; exit(0);
		for (int i=2; i<=sqr; ++i) {
			if (!npri[i]) {
				pri[++pcnt]=i;
				for (int j=1; j<=n; ++j) rec[i][j]=qpow(i, a[j]+1);
			}
			for (int j=1,x; j<=pcnt&&i*pri[j]<=sqr; ++j) {
				npri[x=i*pri[j]]=1;
				for (int k=1; k<=n; ++k) rec[x][k]=rec[i][k]*rec[pri[j]][k]%mod;
				if (!(i%pri[j])) break;
			}
		}
		for (int i=1; i<=n; ++i)
			if (to[i].size()<=sqr) buc[to[i].size()].pb(i);
			else sta.pb(i);
		for (int i=0; i<=sqr; ++i) if (buc[i].size()) {
			base=i; inv=qpow(base-1, mod-2);
			for (auto it:buc[i]) vis[it]=1;
			int cnt=buc[i].size();
			for (int j=tot,u; j; --j) {
				u=tem[j];
				f[u]=1;
				for (auto& v:to[u]) f[u]=f[u]*f[v]%mod;
				if (base==1) f[u]=f[u]*(a[u]+1)%mod;
				else f[u]=f[u]*(rec[i][u]-1)%mod*inv%mod;
				if (vis[u]) {
					ans[u]=f[u];
					if (--cnt==0) break;
				}
			}
			for (auto it:buc[i]) vis[it]=0;
		}
		for (auto it:sta) {
			base=to[it].size(); inv=qpow(base-1, mod-2);
			for (int j=tot,u; j; --j) {
				u=tem[j];
				f[u]=1;
				for (auto& v:to[u]) f[u]=f[u]*f[v]%mod;
				if (base==1) f[u]=f[u]*(a[u]+1)%mod;
				else f[u]=f[u]*(qpow(base, a[u]+1)-1)%mod*inv%mod;
				if (u==it) {ans[u]=f[u]; break;}
			}
		}
		for (int i=1; i<=n; ++i) printf("%lld\n", (ans[i]%mod+mod)%mod);
	}
}

signed main()
{
	freopen("sign.in", "r", stdin);
	freopen("sign.out", "w", stdout);

	n=read();
	for (int i=2; i<=n; ++i) to[fa[i]=read()].pb(i);
	for (int i=1; i<=n; ++i) a[i]=read();
	// force::solve();
	// task1::solve();
	task2::solve();
	
	return 0;
}
posted @   Administrator-09  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
历史上的今天:
2021-06-18 题解 星际旅行
点击右上角即可分享
微信分享提示