2017 CERC

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章