P2351 [SDOI2012]吊灯 题解
首先有一个显然的结论:设所有区块大小为 i,则一定有 i|n 且区块个数为 ni。
一定有一个同色区块保证没有任一节点为异色节点的父节点。
证明(感谢 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;
}
【推荐】博客园的心动:当一群程序员决定开源共建一个真诚相亲平台
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】Flutter适配HarmonyOS 5知识地图,实战解析+高频避坑指南
【推荐】开源 Linux 服务器运维管理面板 1Panel V2 版本正式发布
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从“看懂世界”到“改造世界”:AI发展的四个阶段你了解了吗?
· 协程本质是函数加状态机——零基础深入浅出 C++20 协程
· 编码之道,道心破碎。
· 记一次 .NET 某发证机系统 崩溃分析
· 微服务架构学习与思考:SOA架构与微服务架构对比分析
· 历时半年,我将一个大型asp.net的零代码快速开发平台转成了java
· C#实现语音预处理:降噪、静音检测、自动增益(附Demo源码)
· 推荐五大AI+MCP自动化测试工具!
· 记一次 .NET 某无语的电商采集系统 CPU爆高分析
· Spring Boot 启动优化实践