https://codeforces.com/gym/101620/
解题报告:https://www.cnblogs.com/GerynOhenz/p/8418171.html
Problem J:Justified Jungle
题目描述:给定一个有n
个节点的数,找出所有的整数k,满足在树上删掉k
条边后,形成的每棵树的节点数相同。
solution
首先,k+1
一定是n的因数。随意找一个点做根,求出每棵子树的大小。如果某一个k是答案,则子树大小是n/k+1的倍数的个数应该是k+1
。可以证明这是充要条件。
时间复杂度:O(nlogn)
证明的思路:我个人感觉是这样,每次把最下面的是n/k+1的倍数的子树找出来,割掉它,然后它的父亲大小仍然是n/k+1的倍数,重复操作,直到分割完为止。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+7;
struct edge{
int to;
int next;
};
int n,size[maxn],vis[maxn]={0};
vector<int> e[maxn];
void add_edge(int u,int v){
e[u].push_back(v);
e[v].push_back(u);
}
void build(int x,int pre){
size[x]=1;
for (auto it:e[x]){
if (it!=pre){
build(it,x);
size[x]+=size[it];
}
}
vis[size[x]]++;
}
bool check(int k){
if (n%(k+1)) return 0;
int s=n/(k+1),num=0;
for (int i=s; i<=n; i+=s){
num+=vis[i];
}
return num==(k+1);
}
int main(){
scanf("%d",&n);
int x,y;
for (int i=0; i<n-1; i++){
scanf("%d%d",&x,&y);
add_edge(x,y);
}
build(1,0);
for (int i=1; i<n; i++){
if (check(i)) printf("%d ",i);
}
return 0;
}
/*
8
1 2
2 3
1 4
4 5
6 7
8 3
7 3
output:1 3 7
*/