P2351 [SDOI2012]吊灯 题解

题目传送门

首先有一个显然的结论:设所有区块大小为 \(i\),则一定有 \(i|n\) 且区块个数为 \(\dfrac{n}{i}\)。​

一定有一个同色区块保证没有任一节点为异色节点的父节点。

证明(感谢 wzj423 提供思路):

不妨把每一个颜色抽象为一个点,每一种颜色的父子关系抽象为有向边,则形成一个 DAG。进行拓扑排序并删边,发现一定有,该命题成立。

有了这一结论,显然的,节点的子树个数之和一定为 \(i\)​​ 的倍数。

所以每次统计每个点的子树节点个数再加以判断分为几块,合法即可。

\((f_x+19940105)\mod (x-1)+1<f_x\),可知子节点权值一定大于父节点,因此在枚举时从大到小枚举以优化。枚举判断不多赘述。

View code:

#include<bits/stdc++.h>
using namespace std;

#define ri register int
#define il inline

const int INF=0x3f3f3f3f,N=1.5e6,C=19940105;
int n;
int u[N],size[N],sum[N];

il ll read(){
    ll x=0,y=1;
    char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-')
            y=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=x*10+c-'0';
        c=getchar();
    }
    return x*y;
}

signed main(){
    n=read();
    for(ri i=2;i<=n;i++)
        u[i]=read();
    for(ri i=1;i<=10;i++){
        printf("Case #%d:\n1\n",i);
        if(i!=1)
            for(ri i=2;i<=n;i++)
		    	u[i]=(u[i]+C)%(i-1)+1;
        for(ri i=1;i<=n;i++){
	    	size[i]=1;
	    	sum[i]=0;	
	    } 
	    for(ri i=n;i>1;i--)
	    	size[u[i]]+=size[i];
	    for(ri i=1;i<=n;i++)
	    	sum[size[i]]++;
        for(ri i=2;i<=n;i++){
			int mid=0;
			if(!(n%i)){
				for(ri j=1;i*j<=n;j++)
					mid+=sum[i*j];
				if(mid*i>=n)
                    printf("%d\n",i);
			}
		}
    }
    return 0;
}
posted @ 2021-08-07 15:37  BFNewdawn  阅读(38)  评论(0编辑  收藏  举报