題目大意
給定大小爲n的一棵樹,通過刪除一些邊的方式來拆分這棵樹。問有多少種方法使拆分出的每一個部分大小相等。注意一條邊也不刪也可以算一種方案。輸入量很大,要用快速讀入。
n<=10^6
時間限制 2s
空間限制 1024M
解題思路
首先這些樹的大小一定是n的約數,並且當樹的大小k確定時,分割方案也一定是唯一的。所以我們可以枚舉k,再看看有多少棵樹的大小爲k的整數倍,如果這個數量爲n/k,那麼答案就可以加一。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 1000006
#define fr(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
void read(int &x)
{
char c;
x=0;
for(c=getchar();c<'0' || c>'9';c=getchar());
for(;c>='0' && c<='9';c=getchar()) x=x*10+c-'0';
return;
}
struct poi
{
int x;
poi *nex;
} *a[maxn];
int i,k,n,x,y,s,ans,d[maxn],f[maxn],fa[maxn],siz[maxn];
void link(int x,int y)
{
poi *p=new poi;
p->x=y;
p->nex=a[x];
a[x]=p;
return;
}
void bfs()
{
int i=0,j=1;
poi *p=new poi;
f[1]=1;
while (i<j)
{
i++;
int u=f[i];
siz[u]=1;
for(p=a[u];p;p=p->nex)
if (p->x!=fa[u])
{
fa[p->x]=u;
f[++j]=p->x;
}
}
return;
}
int main()
{
scanf("%d",&n);
fr(i,1,n-1)
{
read(x),read(y);
link(x,y),link(y,x);
}
bfs();
poi *p=new poi;
for(k=n;k;k--)
{
i=f[k];
for(p=a[i];p;p=p->nex)
if (p->x!=fa[i])
siz[i]+=siz[p->x];
}
fr(i,1,n) d[siz[i]]++;
fr(k,1,n)
if (n%k==0)
{
s=0;
fr(i,1,n/k) s+=d[i*k];
if (s==n/k) ans++;
}
printf("%d\n",ans);
return 0;
}