【bzoj4401】塊的計數 結論題
阿新 • • 發佈:2017-12-20
編號 時間復雜度 sdi 約數 blog ros lin bsp style
題目描述
給出一棵n個點的樹,求有多少個si使得整棵樹可以分為n/si個連通塊。
輸入
第一行一個正整數N,表示這棵樹的結點總數,接下來N-1行,每行兩個數字X,Y表示編號為X的結點與編號為Y的結點相連。結點編號的範圍為1-N且編號兩兩不同。
輸出
一行一個整數Ans,表示所求的方案數。
樣例輸入
6
1 2
2 3
2 4
4 5
5 6
樣例輸出
3
題解
結論題
結論:k可行當且僅當子樹大小是k的倍數的節點數有n/k個。
這結論好像挺顯然的(只要你能想出來。。。)
然後就做完了。。。先預處理出每個節點的size,對size維護桶,枚舉n的約數,再枚舉它的倍數求和統計即可。
時間復雜度為 $O(\sum\limits_{k|n}\frac nk=\sum\limits_{k|n}k=n\log\log n)$
#include <cstdio> #include <cctype> #define N 1000010 int head[N] , to[N << 1] , next[N << 1] , cnt , si[N] , v[N]; inline void add(int x , int y) { to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt; } void dfs(int x , int fa) { int i; si[x] = 1; for(i = head[x] ; i ; i = next[i]) if(to[i] != fa) dfs(to[i] , x) , si[x] += si[to[i]]; v[si[x]] ++ ; } inline char nc() { static char buf[100000] , *p1 , *p2; return p1 == p2 && (p2 = (p1 = buf) + fread(buf , 1 , 100000 , stdin) , p1 == p2) ? EOF : *p1 ++ ; } inline int read() { int ret = 0; char ch = nc(); while(!isdigit(ch)) ch = nc(); while(isdigit(ch)) ret = ((ret + (ret << 2)) << 1) + (ch ^ ‘0‘) , ch = nc(); return ret; } int main() { int n = read() , i , x , y , ans = 0; for(i = 1 ; i < n ; i ++ ) x = read() , y = read() , add(x , y) , add(y , x); dfs(1 , 0); for(i = 1 ; i <= n ; i ++ ) { if(!(n % i)) { for(x = 0 , y = i ; y <= n ; y += i) x += v[y]; if(x == n / i) ans ++ ; } } printf("%d\n" , ans); return 0; }
【bzoj4401】塊的計數 結論題