图论训练之十七
分析:
炸看一眼:方案数?怎么算?果断看题解
提取性质:
一:分成若干树的大小只可能是n的约数
二:只要分的大小确定后,如果有分割方案只可能有一种
第二点的性质很好,感性理解
不知道n√n怎么能过1e6
枚举√n约数,再O(N)判断
怎么判断,如果该节点的大小能够被枚举的约数整除,
那么说明该节点有可以分成这么多块的潜质,因为可能有大小满足但是内部不满足的情况
所以还要判断满足的点数*枚举的约数是否等于N
code:
# include <bits/stdc++.h>
using namespace std;
const int root=1;
const int MAXN=1e6+10;
int n,head[MAXN],size[MAXN],tot=0;
struct rec{int to,pre;}a[MAXN*2];
inline int read()
{
int X=0,w=0; char c=0;
while(c<'0'||c>'9') {w|=c=='-';c=getchar();}
while(c>='0'&&c<='9') X=(X<<3)+(X<<1)+(c^48),c=getchar();
return w?-X:X;
}
void adde(int u,int v)
{
a[++tot].pre=head[u];
a[tot].to=v;
head[u]=tot;
}
void dfs1(int u,int fa)
{
size[u]=1;
for (int i=head[u];i;i=a[i].pre){
int v=a[i].to; if (v==fa) continue;
dfs1(v,u);
size[u]+=size[v];
}
}
bool check(int R)
{
int cnt=0;
for (int i=1;i<=n;i++)
if (size[i]%R==0) cnt++;
return n/R==cnt;
}
int main()
{
n=read();
int u,v;
for (int i=1;i<n;i++) {
u=read();v=read();
adde(u,v);adde(v,u);
}
dfs1(root,-1);
int ans=0;
for (int i=1;i<=sqrt(n);i++) {
if (n%i) continue;
if (check(i)) ans++;
if (i!=n/i&&check(n/i)) ans++;
}
printf("%d\n",ans);
return 0;
}