4757. 【NOIP2016提高A组模拟9.4】树上摩托
Description
Sherco是一位经验丰富的魔♂法师。
Sherco在第零次圣杯战争中取得了胜利,并取得了王之宝藏——王の树。
他想把这棵树砍去任意条边,拆成若干棵新树,并装饰在他的摩托上,让他的摩托更加酷炫。
但Sherco认为,这样生成的树不具有美感,于是Sherco想让每棵新树的节点数相同。
他想知道有多少种方法分割这棵树。
Input
第一行一个正整数N,表示这棵树的结点总数。
接下来N-1行,每行两个数字X,Y表示编号为X的结点与编号为Y的结点相连。结点编号的范围为[1,N]。
Output
一个整数,表示方案数。注意,不砍去任何一条边也算作一种方案。
Sample Input
6
1 2
2 3
2 4
4 5
5 6
Sample Output
3
Data Constraint
对于40%的数据,N ≤ 15
对于60%的数据,N ≤ 10^5
对于100%的数据,N ≤ 10^6
数据规模非常大,请使用高效的读入方式。
分析:不难发现,若只要恰好有n/k个子树大小为k的倍数的节点,那么就可以分成题目要求。
代码
#include <cstdio>
#include <string>
#include <cstring>
#include <queue>
#define N 1000005
using namespace std;
struct arr
{
int to, nxt;
}a[N * 2];
int ls[N * 2],siz[N],num[N],f[N],fa[N],l,n;
bool v[N];
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';
}
void add(int x, int y)
{
a[++l].to = y;
a[l].nxt = ls[x];
ls[x] = l;
}
void bfs()
{
int h = 0, t = 1;
f[1] = 1;
while (h < t)
{
h++;
int k = f[h];
siz[k] = 1;
for (int i = ls[k]; i; i = a[i].nxt)
if (a[i].to != fa[k])
{
fa[a[i].to] = k;
f[++t] = a[i].to;
}
}
}
int main()
{
// freopen("sherco8.in","r",stdin);
scanf("%d", &n);
for (int i = 1; i < n; i++)
{
int x, y;
read(x); read(y);
add(x, y);
add(y, x);
}
bfs();
for (int i = n; i >= 1; i--)
{
int u = f[i];
for (int j = ls[u]; j; j = a[j].nxt)
if (a[j].to != fa[u])
siz[u] += siz[a[j].to];
}
for (int i = 1; i <= n; i++)
num[siz[i]]++;
long long ans = 0;
for (int i = 1; i <= n; i++)
if (n % i == 0)
{
int s = 0;
for (int k = 1; k <= n / i; k++)
s+=num[k * i];
if (s == n / i) ans++;
}
printf("%lld", ans);
}