[CF1034C] Region Separation

题目描述

There are $ n $ cities in the Kingdom of Autumn, numbered from $ 1 $ to $ n $ . People can travel between any two cities using $ n-1 $ two-directional roads.

This year, the government decides to separate the kingdom. There will be regions of different levels. The whole kingdom will be the region of level $ 1 $ . Each region of $ i $ -th level should be separated into several (at least two) regions of $ i+1 $ -th level, unless $ i $ -th level is the last level. Each city should belong to exactly one region of each level and for any two cities in the same region, it should be possible to travel between them passing the cities in the same region only.

According to research, for each city $ i $ , there is a value $ a_i $ , which describes the importance of this city. All regions of the same level should have an equal sum of city importances.

Your task is to find how many plans there are to determine the separation of the regions that all the conditions are satisfied. Two plans are considered different if and only if their numbers of levels are different or there exist two cities in the same region of one level in one plan but in different regions of this level in the other plan. Since the answer may be very large, output it modulo $ 10^9+7 $ .

输入格式

The first line contains one integer $ n $ ( $ 1 \leq n \leq 10^6 $ ) — the number of the cities.

The second line contains $ n $ integers, the $ i $ -th of which is $ a_i $ ( $ 1 \leq a_i \leq 10^9 $ ) — the value of each city.

The third line contains $ n-1 $ integers, $ p_1, p_2, \ldots, p_{n-1} $ ; $ p_i $ ( $ p_i \leq i $ ) describes a road between cities $ p_i $ and $ i+1 $ .

题解

\(s=\sum\limits_{i=1}^n a_i\)

设现在要把树分成 \(i\) 份,如何判定是否可以分成 \(i\) 份呢?首先一定要满足 \(i|s\)。钦定树根为 1,定义 \(b_i\)\(i\) 的子树的 \(a\) 的和。那么结论是如果存在至少(其实至多也是) \(i\)\(b_i\) 满足 \(\frac{s}{i}|b_i\)。很明显,一种方案中,一个连通块的点权和等于一个 \(b_i\) 减去若干个 \(b_j\),然后他们如果都是 \(\frac{s}{i}\) 的倍数,那么减完后满足这个连通块也是 \(\frac{s}{i}\) 的倍数,所以满足每个连通块都是 \(\frac{s}{i}\) 的倍数。换句话说,如果 \(\frac{s}{i}|b_i\),那么就把 \(i\) 和父亲的连边断去,就是一个构造。

然而我们如何统计树上有多少个 \(b_j\) 满足 \(\frac{s}{i}|b_j\) 呢?暴力是 \(O(n^2)\)。同时有一个性质是 \(i\le n\),在这里做手脚,把条件转化为 \(i\) 有关的。如果 \(\frac{s}{i}|b_j\),同时 \(\frac{s}{i}|s\),所以 \(\frac{s}{i}|\gcd(b_j,s)\)。定义 \(k=\tfrac{\gcd(b_j,s)}{\frac{s}{i}}\),\(\frac{ks}{i}=\gcd(b_j,s),k\tfrac{s}{\gcd(b_j,s)}=i,\tfrac{s}{\gcd(b_j,s)}|i\)

很成功转成了 \(i\) 的条件,那么就可以直接一个筛法统计了。统计完后要计算方案数,如果可以分成 \(i\) 份,然后枚举上一次是分成几份后再分成这样的,那么 \(dp_i=1+\sum\limits_{j|i}dp_j\)

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e6+5,P=998244353;
int f[N],g[N],n,hd[N],e_num,ret;
LL a[N],s,ans,c[N];
struct edge{
	int v,nxt;
}e[N<<1];
void add_edge(int u,int v)
{
	e[++e_num]=(edge){v,hd[u]};
	hd[u]=e_num;
}
LL gcd(LL x,LL y)
{
	if(!y)	
		return x;
	return gcd(y,x%y);
}
void dfs(int x,int y)
{
	for(int i=hd[x];i;i=e[i].nxt)
		if(e[i].v!=y)
			dfs(e[i].v,x),a[x]+=a[e[i].v];
	LL k=s/gcd(s,a[x]);
	if(k<=n)
		c[k]++;
}
int main()
{
	freopen("xiongaktenioi.in","r",stdin);
	freopen("xiongaktenioi.out","w",stdout);
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%lld",a+i),s+=a[i];
	for(int i=2,x;i<=n;i++)
		scanf("%d",&x),add_edge(x,i);
//	printf("qzmakioi") ;
	dfs(1,0);
//	printf("qzmakioi") ;
	for(int i=n-1;i>=1;i--)
		for(int j=2;j*i<=n;j++)
			c[j*i]+=c[i];
	g[1]=1;
//	printf("qzmakioi") ;
	for(int i=1;i<=n;i++)
	{
		if(s%i==0&&c[i]==i)
		{
			(ret+=g[i])%=P;
			for(int k=2;k*i<=n;k++)
				(g[k*i]+=g[i])%=P;
		}
	}
	printf("%d",ret);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值