首先显然如果块大小固定,方案唯一。如果在方案中将一个点和其父亲分开,那么这个点的子树大小一定是块大小k的倍数。并且如果能找到n/k个点(当然n是k的倍数)满足这条,一定可以以此构造一个划分方案,看起来挺显然的感(xia)性(cai)证(jie)明(lun)一下。于是统计子树大小即可。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 1000010 int n,p[N],size[N],t=0,cnt[N],ans; struct data{int to,nxt; }edge[N<<1]; void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;} void dfs(int k,int from) { size[k]=1; for (int i=p[k];i;i=edge[i].nxt) if (edge[i].to!=from) { dfs(edge[i].to,k); size[k]+=size[edge[i].to]; } cnt[size[k]]++; } int main() { #ifndef ONLINE_JUDGE freopen("bzoj4401.in","r",stdin); freopen("bzoj4401.out","w",stdout); const char LL[]="%I64d "; #else const char LL[]="%lld "; #endif n=read(); for (int i=1;i<n;i++) { int x=read(),y=read(); addedge(x,y),addedge(y,x); } dfs(1,1); for (int i=1;i<=n;i++) if (n%i==0) { int tot=0; for (int j=i;j<=n;j+=i) tot+=cnt[j]; if (tot==n/i) ans++; } cout<<ans; return 0; }