洛谷 p2351 [SDOI2012]吊灯
题目分析
看完这个题后,我们可以得出一个很显然的结论,要保证一颗节点数为n的树可以分成若干个大小
为i的连通块,一定有i | n且定有n/i个节点的子树节点数之和(包括其本身)是i的倍数,(很显然,但)
不会证
所以思路就很简单了,统计每个点的子节点个数,然后进行判断就行了
最开始统计个数用了dfs(本题这么明显的优化提示没注意) 期望得分70,但统计倍数个数的时候时
间复杂度炸了,被卡到40。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
using namespace std;
const int maxn=2e6+10;
inline int read(){
int ret=0;
int f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-f;
ch=getchar();
}
while(ch<='9'&&ch>='0'){
ret=ret*10+(ch^'0');
ch=getchar();
}
return f*ret;
}
int num[maxn];
int n;
int size[maxn];
int f[maxn];
int main(){
freopen("a.in","r",stdin);
n=read();
int t=10;
while(t--){
for(int i=2;i<=n;i++){
if(t==9){
f[i]=read();
}
else{
f[i]=(f[i]+19940105)%(i-1)+1;
}
}
memset(num,0,sizeof(num));
for(int i=1;i<=n;i++){
size[i]=1;
}
for(int i=n;i>1;i--){
// cout<<f[i]<<endl;
size[f[i]]+=size[i];
}
for(int i=1;i<=n;i++){
// cout<<size[i]<<endl;
num[size[i]]++;
}
cout<<"Case #"<<10-t<<':'<<endl;
for(int l=1,r;l<=n;l=r+1){
r=n/(n/l);//整除优化,能稍微快一点,把此处的n优化为根号n
int t=0;
for(int j=1;r*j<=n;++j) {
t+=num[r*j];
}
if(t*r==n) cout<<r<<endl;
}
}
return 0;
}
完结撒花!