bzoj4401: 块的计数

首先,块的大小确定的话,可以发现方案最多只有1种

然后就可以O(nsqrt(n))搞,不过会TLE

接着我们又发现,一个节点可以作一个块的根,当且仅当该节点的size能被块的大小整除

然后就可以O(nlogn)搞了

详见代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#define N 1000006
#define M 2000006

using namespace std;
inline int read(){
	int ret=0;char ch=getchar();
	while (ch<'0' || ch>'9') ch=getchar();
	while ('0'<=ch && ch<='9'){
		ret=ret*10-48+ch;
		ch=getchar();
	}
	return ret;
}

struct edge{
	int adj,next;
	edge(){}
	edge(int _adj,int _next):adj(_adj),next(_next){}
} e[M];
int n,g[N],m;
void AddEdge(int u,int v){
	e[++m]=edge(v,g[u]);g[u]=m;
	e[++m]=edge(u,g[v]);g[v]=m;
}

int cnt[N];
int size[N];
bool vis[N];
void dfs(int u){
	vis[u]=1;size[u]=1;
	for (int i=g[u];i;i=e[i].next){
		int v=e[i].adj;
		if (vis[v]) continue;
		dfs(v);
		size[u]+=size[v];
	}
	++cnt[size[u]];
}

int main(){
	n=read();
	memset(g,0,sizeof(g));m=1;
	for (int i=1;i<n;++i) AddEdge(read(),read());
	memset(cnt,0,sizeof(cnt));
	memset(vis,0,sizeof(vis));
	dfs(1);
	int ans=0;
	for (int i=1;i<=n;++i){
		for (int j=2;i*j<=n;++j)
			cnt[i]+=cnt[i*j];
		if (i*cnt[i]==n) ++ans;
	}
	printf("%d\n",ans);
	return 0;
}

  

  

posted @ 2016-01-14 11:38  wangyurzee  阅读(749)  评论(0编辑  收藏  举报