您的位置:首页 > 其它

【NOIP模拟】树上摩托

2016-09-04 15:38 387 查看

Description

Sherco是一位经验丰富的魔♂法师。

Sherco在第零次圣杯战争中取得了胜利,并取得了王之宝藏——王の树。

他想把这棵树砍去任意条边,拆成若干棵新树,并装饰在他的摩托上,让他的摩托更加酷炫。

但Sherco认为,这样生成的树不具有美感,于是Sherco想让每棵新树的节点数相同。

他想知道有多少种方法分割这棵树。

Solution

这题一看上去就很难的样子,一直找到所有的约数之后,然后在逐个的找有多少种情况,搞的最后只能打40分的暴搜。

其实有两个很重要的性质:

1、分割完的每个树的节点个数都是n的约数(这个很显然)

2、对于每种约数的分割方案只有一种(感性的证明一下,如果在x点之上的边割掉了,x点及以下的所有点是k的倍数,x以上的所有点是k的倍数,必须要在加进k个点才能改变,但是那样是早已被割出来了的)

有了这个东西之后,我们枚举k,然后找到所有子节点的个数是k的倍数的节点,然后统计起来,如果数量等于nk,那么答案就加1。

怎么找这些点呢,用bz[i]表示节点数为i的点的个数。

注意会爆栈

dfs找儿子的节点个数要改成用bfs来找。

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
#define rep(i,a) for(i=first[a];i;i=next[i])
using namespace std;
const int maxn=1000007;
int i,j,k,l,t,n,m,ans;
int first[maxn*2],last[maxn*2],next[maxn*2],num;
int size[maxn*2];
int bz[maxn*2];
int data[maxn*2],f[maxn*2],tuo[maxn*2];
bool az[maxn];
void add(int x,int y){
last[++num]=y,next[num]=first[x],first[x]=num;
}
void bfs(int x){
int i,head=0,tail=1,now;
data[1]=x;az[1]=1;
while(head<tail){
now=data[++head];
rep(i,now){
if(!az[last[i]]){
az[last[i]]=1;
f[last[i]]=now;
data[++tail]=last[i];
}
}
}
memset(az,0,sizeof(az));
fo(i,1,tail){
if(!az[data[i]]){
az[data[i]]=1;
tuo[++tuo[0]]=data[i];
}
}
}
int main(){
scanf("%d",&n);
fo(i,1,n-1){
scanf("%d%d",&k,&l);
add(k,l),add(l,k);
}
bfs(1);
fod(i,n,1){
size[tuo[i]]+=1;
size[f[tuo[i]]]+=size[tuo[i]];
bz[size[tuo[i]]]+=1;
}
fo(k,1,n){
if(n%k==0){
i=k,j=0;
while(i<=n){
j+=bz[i];
i+=k;
}
if(j==n/k)ans++;
}
}
printf("%d\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: