【bzoj4401】块的计数(水dfs)
题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4401
假设把树划分为x个节点作一块,那么显然只有当x|n的时候才可能存在划分方案,并且这种划分方案是唯一的。
并且对于一棵树,只有当有n/x个节点的子树大小%x==0的时候才可能存在划分方案,因为如果把一棵树的根节点及其所在的块切掉,那么剩下的子树若存在划分方案,一定满足这些子树的节点个数%x==0。
所以这道题就变成一道水题了。
代码(我本来想着用bfs代替dfs会跑得快一点,然而似乎并没有什么卵用):
#include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<ctime> #include<algorithm> #include<queue> #include<vector> #include<map> #define ll long long #define min(a,b) (a<b?a:b) #define max(a,b) (a>b?a:b) ll read() { ll tmp=0; char f=1,c=getchar(); while(c<'0'||'9'<c){if(c=='-')f=-1; c=getchar();} while('0'<=c&&c<='9'){tmp=tmp*10+c-'0'; c=getchar();} return tmp*f; } using namespace std; int size[1000010],q[1000010],fa[1000010],cnt[1000010]; int fir[1000010],ne[2000010],to[2000010]; int n,tot=0; void add(int x,int y){to[++tot]=y; ne[tot]=fir[x]; fir[x]=tot;} int main() { int i; n=read(); for(i=1;i<n;i++){ int x=read(),y=read(); add(x,y); add(y,x); } int h=1,t=1; q[1]=1; fa[1]=-1; while(h<=t){ for(i=fir[q[h]];i;i=ne[i]) if(!fa[to[i]])q[++t]=to[i],fa[to[i]]=q[h]; ++h; } for(i=n;i;i--){ size[q[i]]=1; for(int j=fir[q[i]];j;j=ne[j]) if(to[j]!=fa[q[i]])size[q[i]]+=size[to[j]]; ++cnt[size[q[i]]]; } int ans=0; for(i=1;i<=n;i++) if(n%i==0){ int tmp=0; for(int j=i;j<=n;j+=i)tmp+=cnt[j]; if(tmp*i==n)++ans; } printf("%d\n",ans); return 0; }