【Luogu】P2351吊灯(脑洞后模拟)
这题要智商qwq。玩不来玩不来。
观察到(个P,能观察到的全都是dalao)x是解的充要条件是至少有n/x个节点的size是x的倍数。
证明请看这里
然后这题就变模拟了呀。
#include<cstdio> #include<cstring> #include<cctype> #include<algorithm> #include<cstdlib> #define maxn 2000010 using namespace std; inline long long read(){ long long num=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-') f=-1; ch=getchar(); } while(isdigit(ch)){ num=num*10+ch-'0'; ch=getchar(); } return num*f; } int father[maxn]; int size[maxn]; int s[maxn],tot; struct Edge{ int next,to; }edge[maxn]; int head[maxn],num; inline void add(int from,int to){ edge[++num]=(Edge){head[from],to}; head[from]=num; } int d[maxn]; void dfs(int x,int fa){ size[x]=1; for(int i=head[x];i;i=edge[i].next){ int to=edge[i].to; if(to==fa) continue; dfs(to,x); size[x]+=size[to]; } d[size[x]]++; return; } int main(){ int n=read(); for(int i=1;i<=n;++i) if(n%i==0) s[++tot]=i; for(int i=2;i<=n;++i){ father[i]=read(); add(father[i],i); } dfs(1,1); printf("Case #1:\n"); for(int i=1;i<=tot;++i){ int now=0; for(int j=s[i];j<=n;j+=s[i]){ now+=d[j]; if(now>=n/s[i]){ printf("%d\n",s[i]); break; } } } for(int i=1;i<=9;++i){ memset(d,0,sizeof(d)); for(int j=2;j<=n;++j) father[j]=(father[j]+19940105)%(j-1)+1; printf("Case #%d:\n",i+1); for(int j=1;j<=n;++j) size[j]=1; for(int j=n;j>=1;--j){ size[father[j]]+=size[j]; d[size[j]]++; } for(int j=1;j<=tot;++j){ int now=0; for(int k=s[j];k<=n;k+=s[j]){ now+=d[k]; if(now>=n/s[j]){ printf("%d\n",s[j]); break; } } } } return 0; }