要将整棵树分成大小相等的连通块,那么首先我们可以肯定的是每块大小x一定是n的约数,且恰好分成$\frac{n}{x}$块,所以我有了这样一个思路:向下深搜,如果一个节点的size=x,就把这个子树砍掉做成一个连通块,并更新父亲及祖先的size,这样递归地切,如果最后size[1]==0就表示所有的点都被切成了一个连通块……
然后我只得了40分= =明显会T啊……
事实上有一个更进一步的结论:上个做法中每次“砍”的点一定是size[i]%x==0的点!所以我们只需要判一下size[i]%x==0的点的数量是否等于$\frac{n}{x}$即可……
这个算法就可以顺利过掉所有数据了(复杂度O(NloglogN))
1 /************************************************************** 2 Problem: 3004 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:3888 ms 7 Memory:20024 kb 8 ****************************************************************/ 9 10 //Huce #3 C 11 #include<cmath> 12 #include<vector> 13 #include<cstdio> 14 #include<cstdlib> 15 #include<cstring> 16 #include<iostream> 17 #include<algorithm> 18 #define rep(i,n) for(int i=0;i<n;++i) 19 #define F(i,j,n) for(int i=j;i<=n;++i) 20 #define D(i,j,n) for(int i=j;i>=n;--i) 21 using namespace std; 22 23 int getint(){ 24 int v=0,sign=1; char ch=getchar(); 25 while(ch<'0'||ch>'9') {if (ch=='-') sign=-1; ch=getchar();} 26 while(ch>='0'&&ch<='9') {v=v*10+ch-'0'; ch=getchar();} 27 return v*sign; 28 } 29 typedef long long LL; 30 const int N=1200010,INF=~0u>>2; 31 /*******************tamplate********************/ 32 int Case=0,n,fa[N],sz[N],a[N],c[N]; 33 bool jud(int x){ 34 int cnt=0; 35 for(int i=x;i<=n;i+=x) cnt+=c[i]; 36 return cnt==n/x; 37 } 38 void solve(){ 39 memset(sz,0,sizeof sz); 40 memset(c,0,sizeof c); 41 printf("Case #%d:\n",++Case); 42 D(i,n,1){ 43 sz[i]++; 44 sz[fa[i]]+=sz[i]; 45 c[sz[i]]++; 46 } 47 F(i,1,n) if (n%i==0) 48 if (jud(i)) printf("%d\n",i); 49 } 50 void change(){ 51 F(i,2,n) fa[i]=(fa[i]+19940105)%(i-1)+1; 52 } 53 int main(){ 54 #ifndef ONLINE_JUDGE 55 freopen("input.txt","r",stdin); 56 // freopen("output.txt","w",stdout); 57 #endif 58 n=getint(); fa[1]=0; 59 F(i,2,n) scanf("%d%*c",&fa[i]); 60 solve(); 61 F(i,1,9){ 62 change(); 63 solve(); 64 } 65 return 0; 66 }