1. 程式人生 > >bzoj 4401 塊的計數 思想+模擬+貪心

bzoj 4401 塊的計數 思想+模擬+貪心

sqrt discus == 操作 興趣 貪心 input bsp 找到

塊的計數

Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 455 Solved: 261
[Submit][Status][Discuss]

Description

小Y最近從同學那裏聽說了一個十分牛B的高級數據結構——塊狀樹。聽說這種數據結構能在sqrt(N)的時間內維護樹上的各種信息,十分的高效。當然,無聊的小Y對這種事情毫無興趣,只是對把樹分塊這個操作感到十分好奇。他想,假如能把一棵樹分成幾塊,使得每個塊中的點數都相同該有多優美啊!小Y很想知道,能有幾種分割方法使得一棵樹變得優美。小Y每次會畫出一棵樹,但由於手速太快,有時候小Y畫出來的樹會異常地龐大,令小Y感到十分的苦惱。但是小Y實在是太想知道答案了,於是他找到了你,一個天才的程序員,來幫助他完成這件事。

Input

第一行一個正整數N,表示這棵樹的結點總數,接下來N-1行,每行兩個數字X,Y表示編號為X的結點與編號為Y的結點相連。結點編號的範圍為1-N且編號兩兩不同。

Output

一行一個整數Ans,表示所求的方案數。

Sample Input

6
1 2
2 3
2 4
4 5
5 6

Sample Output

3

HINT

100%的數據滿足N<=1000000。

Source

首先隨便選一個根進行dfs得到size[x]表示以x為根節點的子樹的大小。然後我們假設答案為t,需要判斷t是否可行。首先顯然需要t|n。

顯然每一個塊有且僅有一個根,定義為這個塊的最高點。然後我們發現一個點x是塊的根的必要條件是t|size[x]!這個是顯然的。然後我

們統計有多少個size[x]被t整除,如果與n/t相同則合法,否則一定小於n/t,因此一定不合法。

 1 #include<cstring>
 2 #include<cmath>
 3 #include<algorithm>
 4 #include<iostream>
 5 #include<cstdio>
 6 
 7 #define N 1000007
 8 #define ll long long
 9
10 using namespace std; 11 inline int read() 12 { 13 int x=0,f=1;char ch=getchar(); 14 while (ch<0||ch>9){if (ch==-)f=-1;ch=getchar();} 15 while (ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();} 16 return x*f; 17 } 18 19 int n,ans; 20 int Head[N],ret[N<<1],Next[N<<1],tot; 21 int size[N],st[N]; 22 23 inline void ins(int u,int v) 24 { 25 ret[++tot]=v; 26 Next[tot]=Head[u]; 27 Head[u]=tot; 28 } 29 void dfs(int u,int f) 30 { 31 size[u]=1; 32 for (int i=Head[u];i;i=Next[i]) 33 { 34 if (ret[i]==f) continue; 35 dfs(ret[i],u); 36 size[u]+=size[ret[i]]; 37 } 38 st[size[u]]++; 39 } 40 int main() 41 { 42 n=read(); 43 for (int i=1;i<n;i++) 44 { 45 int u=read(),v=read(); 46 ins(u,v);ins(v,u); 47 } 48 dfs(1,0); 49 for (int i=1;i<=n;i++) 50 if (n%i==0) 51 { 52 int sum=0; 53 for (int j=i;j<=n;j+=i) 54 sum+=st[j]; 55 if (sum==n/i) ans++; 56 } 57 printf("%d\n",ans); 58 }

bzoj 4401 塊的計數 思想+模擬+貪心