BZOJ 3004 吊灯 树形DP
2015-05-14 14:40
197 查看
题目大意:给定一棵树,要求将这棵树分成nk\frac nk个连通块,每块大小为kk,求所有可行的kk
首先kk一定是nn的约数。(废话
然后我们有一个结论:某个kk满足条件当且仅当存在nk\frac nk个节点满足以每个节点为根的子树大小都是kk的倍数
证明:
首先不可能存在超过nk\frac nk个节点满足以每个节点为根的子树大小都是kk的倍数,这是废话
首先证明必要性:
假设我们已经有了一组合法的方案,那么对于每一个连通块,我们找到这个连通块中深度最小的节点,以这个节点为根的子树大小一定是kk的倍数
由于这样的节点有nk\frac nk个,因此必要性得证
下面来证明充分性:
假设现在我们已经找到了nk\frac nk个节点满足以每个节点为根的子树大小都是kk的倍数,那么:
首先我们从根节点出发开始DFS,每遇到一个节点满足以这个节点为根的子树大小是kk的倍数,就把这个节点为根的子树砍掉
这样做之后,我们得到了一个连通块和一些子树,其中连通块的大小为kk的倍数,且除根节点外其余nk−1\frac nk-1个节点都在那些子树中
对每个子树重复这一操作,一定能得到一组合法的方案
因此充分性得证
然后就好办了,我们搞出每个节点的sizesize(这里不要DFS,会T掉),然后令fif_i表示大小为ii的子树个数,对于每个约数在ff数组中扫一遍即可
时间复杂度O(10∗σ(n))=O(10∗nloglogn)O(10*\sigma(n))=O(10*nloglogn)
首先kk一定是nn的约数。(废话
然后我们有一个结论:某个kk满足条件当且仅当存在nk\frac nk个节点满足以每个节点为根的子树大小都是kk的倍数
证明:
首先不可能存在超过nk\frac nk个节点满足以每个节点为根的子树大小都是kk的倍数,这是废话
首先证明必要性:
假设我们已经有了一组合法的方案,那么对于每一个连通块,我们找到这个连通块中深度最小的节点,以这个节点为根的子树大小一定是kk的倍数
由于这样的节点有nk\frac nk个,因此必要性得证
下面来证明充分性:
假设现在我们已经找到了nk\frac nk个节点满足以每个节点为根的子树大小都是kk的倍数,那么:
首先我们从根节点出发开始DFS,每遇到一个节点满足以这个节点为根的子树大小是kk的倍数,就把这个节点为根的子树砍掉
这样做之后,我们得到了一个连通块和一些子树,其中连通块的大小为kk的倍数,且除根节点外其余nk−1\frac nk-1个节点都在那些子树中
对每个子树重复这一操作,一定能得到一组合法的方案
因此充分性得证
然后就好办了,我们搞出每个节点的sizesize(这里不要DFS,会T掉),然后令fif_i表示大小为ii的子树个数,对于每个约数在ff数组中扫一遍即可
时间复杂度O(10∗σ(n))=O(10∗nloglogn)O(10*\sigma(n))=O(10*nloglogn)
[code]#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 1201001 using namespace std; int n; int divisors[2020],tot; int fa[M],size[M],f[M]; void Initialize() { memset(size,0,sizeof size); memset(f,0,sizeof f); } void Decomposition(int n) { int i; for(i=1;i*i<n;i++) if(n%i==0) divisors[++tot]=i,divisors[++tot]=n/i; if(i*i==n) divisors[++tot]=i; sort(divisors+1,divisors+tot+1); } namespace IStream{ #define L (1<<16) char Get_Char() { static char buffer[L],*S,*T; if(S==T) { T=(S=buffer)+fread(buffer,1,L,stdin); if(S==T) return EOF; } return *S++; } int Get_Int() { int re=0; char c=Get_Char(); while(c<'0'||c>'9') c=Get_Char(); while(c>='0'&&c<='9') re=(re<<1)+(re<<3)+(c-'0'),c=Get_Char(); return re; } } int main() { //freopen("3004.in","r",stdin); //freopen("3004.out","w",stdout); using namespace IStream; int T,i,j; cin>>n; Decomposition(n); for(T=1;T<=10;T++) { printf("Case #%d:\n",T); Initialize(); for(i=2;i<=n;i++) { if(T==1) fa[i]=Get_Int(); else fa[i]=(fa[i]+19940105)%(i-1)+1; } for(i=n;i;i--) size[fa[i]]+=++size[i]; for(i=1;i<=n;i++) f[size[i]]++; for(i=1;i<=tot;i++) { int temp=0; for(j=divisors[i];j<=n;j+=divisors[i]) temp+=f[j]; if(temp==n/divisors[i]) printf("%d\n",divisors[i]); } } return 0; }
相关文章推荐
- [bzoj3004][SDOI2012]吊灯——樹形DP
- [BZOJ1040][luogu2607][ZJOI2008]骑士(树形dp)
- BZOJ_1304_[CQOI2009]叶子的染色_树形DP
- [BZOJbegin][NOIP十连测第五场]Walk(数学相关+树形dp)
- BZOJ 4824 [Cqoi2017]老C的键盘 ——树形DP
- BZOJ1304 CQOI2009叶子的染色(树形dp)
- 【bzoj1040】骑士[ZJOI2008](树形dp)
- BZOJ 2427 /HAOI 2010 软件安装 tarjan缩点+树形DP
- BZOJ 1304: [CQOI2009]叶子的染色 树形dp
- bzoj 2111: [ZJOI2010]Perm 排列计数【树形dp+lucas】
- bzoj 2427: [HAOI2010]软件安装(Trajan+树形DP)
- HYSBZ/BZOJ 1040 [ZJOI2008] 骑士 - 基环树&树形dp
- 【BZOJ-3573】米特运输 树形DP
- (树形DP) bzoj 4033
- 【BZOJ 3090】 树形DP
- bzoj 1907(树形dp)
- 【bzoj1060】[ZJOI2007]时态同步 树形dp
- bzoj 3611: [Heoi2014]大工程 虚树+树形dp
- 【BZOJ2286】【SDOI2011】消耗战 [虚树][树形DP]
- BZOJ 3037 创世纪 树形DP