[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 ai , 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 109+7 .
输入格式
The first line contains one integer n ( 1≤n≤106 ) — the number of the cities.
The second line contains n integers, the i -th of which is ai ( 1≤ai≤109 ) — the value of each city.
The third line contains n−1 integers, p1,p2,…,pn−1 ; pi ( pi≤i ) describes a road between cities pi and i+1 .
题解
设 s=n∑i=1ai
设现在要把树分成 i 份,如何判定是否可以分成 i 份呢?首先一定要满足 i|s。钦定树根为 1,定义 bi 为 i 的子树的 a 的和。那么结论是如果存在至少(其实至多也是) i 个 bi 满足 si|bi。很明显,一种方案中,一个连通块的点权和等于一个 bi 减去若干个 bj,然后他们如果都是 si 的倍数,那么减完后满足这个连通块也是 si 的倍数,所以满足每个连通块都是 si 的倍数。换句话说,如果 si|bi,那么就把 i 和父亲的连边断去,就是一个构造。
然而我们如何统计树上有多少个 bj 满足 si|bj 呢?暴力是 O(n2)。同时有一个性质是 i≤n,在这里做手脚,把条件转化为 i 有关的。如果 si|bj,同时 si|s,所以 si|gcd。定义 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);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Apifox不支持离线,Apipost可以!
· 历时 8 年,我冲上开源榜前 8 了!
· 零经验选手,Compose 一天开发一款小游戏!
· Trae 开发工具与使用技巧
· 通过 API 将Deepseek响应流式内容输出到前端