图论训练之十七

分析:

炸看一眼:方案数?怎么算?果断看题解

提取性质:

一:分成若干树的大小只可能是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
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/wzxbeliever/p/11788671.html