题意
每一轮可以砍掉若干条边,满足每个连通块权值相等,求砍树方案数.
两种方案不同,当且仅当至少存在一轮,剩余的连通块不完全相同.
考虑如果把树分成 k k k份,那么每个连通块的权值为 S k \frac{S}{k} kS
我们 d f s dfs dfs这棵树,若存在一颗子树的权值等于 S k \frac{S}{k} kS,显然需要砍掉这个儿子和父亲的边
这样重复做下去,发现需要砍掉所有满足 S k ∣ s u \frac{S}{k}|s_u kS∣su的 u u u与父亲的边
我们定义 f [ k ] f[k] f[k]表示
f [ k ] = ∑ i = 1 n [ S k ∣ s i ] f[k]=\sum\limits_{i=1}^n [\frac{S}{k}|s_i] f[k]=i=1∑n[kS∣si]
一种划分要么无解,有解必然只有唯一解,且满足 f [ k ] = = k f[k]==k f[k]==k
若我们处理了这样的 f f f数组就知道哪些划分是有解的
定义 d p [ i ] dp[i] dp[i]表示最后一轮的结果是 k k k划分的方案数,有转移
d p [ k ] = ∑ k ∣ j d p [ j ] dp[k]=\sum\limits_{k|j}dp[j] dp[k]=k∣j∑dp[j]
问题变成求解 f f f数组来给 d p dp dp数组赋上初值
求 f f f数组,对于每个固定的 k k k可以花 O ( n ) O(n) O(n)的时间检验
由于 S S S很大,枚举因子的想法也不可行,复杂度达到 O ( n 2 ) O(n^2) O(n2)
f [ k ] = ∑ i = 1 n [ S k ∣ s i ] f[k]=\sum\limits_{i=1}^n [\frac{S}{k}|s_i] f[k]=i=1∑n[kS∣si]
观察到 S k ∣ s i \frac{S}{k}|s_i kS∣si的条件为
s i = a ∗ S k s_i=a*\frac{S}{k} si=a∗kS
也就是 S k ∣ s i \frac{S}{k}|s_i kS∣si, S k ∣ S \frac{S}{k}|S kS∣S,则有 S k ∣ g c d ( s i , S ) \frac{S}{k}|gcd(s_i,S) kS∣gcd(si,S)
有 S g c d ( S , s i ) ∣ k \frac{S}{gcd(S,s_i)}|k gcd(S,si)S∣k
于是合法的 k k k容易求,只需要枚举 S g c d ( S , s i ) \frac{S}{gcd(S,s_i)} gcd(S,si)S的倍数即可
#include <iostream>
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e6+10;
const int mod = 1e9+7;
int n,f[maxn],s[maxn],dp[maxn],c[maxn];
vector<int>vec[maxn];
void dfs(int u,int fa)
{
for( auto v:vec[u] )
{
if( v==fa ) continue;
dfs( v,u );
s[u] += s[v];
}
}
int gcd(int a,int b){ return b==0?a:gcd(b,a%b); }
void initF()
{
for(int i=1;i<=n;i++)
{
int x = s[1]/gcd( s[i],s[1] );
if( x<=n ) c[x]++;
}
for(int i=1;i<=n;i++)
{
for(int j=i;j<=n;j+=i) f[j] += c[i];
}
}
signed main()
{
cin >> n;
for(int i=1;i<=n;i++) scanf("%lld",&s[i] );
for(int i=1;i<n;i++)
{
int x; scanf("%lld",&x );
vec[x].push_back( i+1 );
vec[i+1].push_back( x );
}
dfs( 1,0 );
initF();
int ans = 0;
dp[1] = 1;
for(int i = 1;i <= n;++ i)
if( f[i] == i )
{
for(int j = i << 1;j <= n;j += i)
dp[j] = ( dp[j] + dp[i] )%mod;
ans = ( ans + dp[i] )%mod;
}
cout << ans;
}