您的位置:首页 > 产品设计 > UI/UE

hdu 5329 Question for the Leader

2015-08-03 20:04 369 查看
hdu 5329 Question for the Leader

题意:

给出一个有n个点的图,这个图是由一个基环 + 若干外向树组成,问能否把这个图分成 k个 大小为n/k 的 连通的子图,问k有多少种。

限制:

1 <= n <= 1e5

思路:

主要是一个性质:

对于一棵树,如果可以把这棵树分成大小都为k的n/k份,那子树大小是k的倍数的节点恰好有n/k个。(任意选定一个根)

详细见多校官方题解

http://blog.sina.com.cn/u/5657719201

/*hdu 5329 Question for the Leader
题意:
给出一个有n个点的图,这个图是由一个基环 + 若干外向树组成,问能否把这个图分成 k个 大小为n/k 的 连通的子图,问k有多少种。
限制:
1 <= n <= 1e5
思路:
主要是一个性质:
对于一棵树,如果可以把这棵树分成大小都为k的n/k份,那子树大小是k的倍数的节点恰好有n/k个。(任意选定一个根)
详细见多校官方题解
*/
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
#define PB push_back
const int N = 1e5 + 5;
int a
;

int cir
, cir_tot;
bool in_cir
;

int tree_sz
;
int cnt
;

vector<int> G
;

int fa
;
void init_bcj(int n) {
for(int i = 0; i <= n; ++i)
fa[i] = i;
}
int get_fa(int x) {
if(x != fa[x]) return fa[x] = get_fa(fa[x]);
return x;
}

int dfs(int u, int fa) {
tree_sz[u] = 1;
for(int i = 0; i < G[u].size(); ++i) {
int ch = G[u][i];
if(ch == fa || in_cir[ch]) continue;
tree_sz[u] += dfs(ch, u);
}
return tree_sz[u];
}

int sum
, sum_cnt
;
bool ok(int bei, int have, int n) {
for(int i = 0; i < bei; ++i)
sum_cnt[i] = 0;
sum[0] = tree_sz[cir[0]] % bei;
++sum_cnt[sum[0]];
for(int i = 1; i < cir_tot; ++i) {
sum[i] = (sum[i - 1] + tree_sz[cir[i]]) % bei;
++sum_cnt[sum[i]];
}
if(sum_cnt[0] + have == n / bei) return true;
int last = cir_tot - 1;
for(int i = 0; i < cir_tot - 1; ++i) {
--sum_cnt[sum[i]];
int tmp = sum[i];
sum[i] = (sum[last] + tree_sz[cir[i]]) % bei;
++sum_cnt[sum[i]];
if(sum_cnt[tmp] + have == n / bei) return true;
last = i;
}
return false;
}

void gao(int n) {
cir_tot = 0;
for(int i = 1; i <= n; ++i) {
G[i].PB(a[i]);
G[a[i]].PB(i);
int fx = get_fa(i);
int fy = get_fa(a[i]);
if(fx != fy) fa[fy] = fx;
else if(cir_tot == 0){
cir[cir_tot++] = i;
in_cir[i] = 1;
}
}

int nxt = a[cir[0]];
while(nxt != cir[0]) {
cir[cir_tot++] = nxt;
in_cir[nxt] = 1;
nxt = a[nxt];
}

for(int i = 1; i <= n; ++i) {
if(in_cir[i]) dfs(i, -1);
}

for(int i = 1; i <= n; ++i)
if(!in_cir[i]) ++cnt[tree_sz[i]];

for(int i = 1; i <= n; ++i) {
for(int j = 2 * i; j <= n; j += i) {
cnt[i] += cnt[j];
}
}

int ans = 0;
for(int i = 1; i <= n; ++i) {
if(n % i) continue;
if(ok(i, cnt[i], n)){
++ans;
}
}
printf("%d\n", ans);
}

void init(int n) {
init_bcj(n);
memset(in_cir, 0, sizeof(in_cir));
memset(tree_sz, 0, sizeof(tree_sz));
memset(cnt, 0, sizeof(cnt));
for(int i = 0; i <= n; ++i)
G[i].clear();
}

int main() {
int n;
while(scanf("%d", &n) != EOF) {
init(n);
for(int i = 1; i <= n; ++i){
scanf("%d", &a[i]);
}
gao(n);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: