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
*/