完全平方数
完全平方数
这是将我引上莫比乌斯反演的第一题 , 传送门:完全平方数
题目大意:求第 个不是完全平方数的倍数的数。
暴力似乎很爽,确实。
但可以以一个优美的算法切掉这一题—— 。
优雅啊!
在一个大佬的帮助下——初一被清华锁定的 lzc 大佬——我明白了这道经典题的解法。
进入正题:
注:[p]表示,若 p 为真,其值为 1,否则为 0
莫比乌斯函数 :默认你已懂其数学定义。
性质一:
略作证明:
前置知识——二项式定理:
证明略。
现证性质一
记 表示 的不同质因子的个数
若 ,则有:
若 ,则易得
证毕。
那么如何做此题呢?
因为 的定义,我们很容易想到如果一个数是完全平方数,那么它的 就必然是 ,否则就是 或 。
那第 个非完全平方数的倍数,记作 , 就要满足 且是所有满足此条中最小的(不要问我为何,你要知道,若 是完全平方数的倍数,那么它的贡献是 )
好,我们设
那么, 是不是完全平方数的倍数就可以表示为
代入关于 的式子,有:
现在进入推导式子,一波骚操作:
先套性质一,然后地球人都明白 , 再改为先枚举 的形式······然后就差不多了,康康下边
没了
显然,这是 的( 提前筛出来)。
然后加上二分猜一个答案,用这种方法 , 时间复杂度
然后加个数论分块优化(不过优化效果不大) , 时间复杂度
代码如下:
#include<cstdio> #include<cmath> #include<iostream> using namespace std; typedef long long LL; const int N = 1e5; int T , vis[N + 5] , prime[N + 5] , mu[N + 5] , tot; LL k; inline void getmu() { mu[1] = 1 , vis[1] = 1; for(register int i = 2; i <= N; i++) { if (!vis[i]) prime[++tot] = i , mu[i] = -1; for(register int j = 1; j <= tot && prime[j] * i <= N; j++) { vis[prime[j] * i] = 1; if (i % prime[j] == 0) break; mu[prime[j] * i] = -mu[i]; } } for(register int i = 1; i <= N; i++) mu[i] += mu[i - 1]; } inline bool check(int m) { int res = 0; LL j; for(register int i = 1; i * i <= m; i = j + 1) { j = floor(sqrt(m / (m / (i * i)))); res += (LL)(m / (i * i)) * (mu[j] - mu[i - 1]); } return res >= k; } inline LL slove() { LL l = k , r = k << 1 , res = 2e9 , mid; while (l <= r) { mid = (l + r) >> 1; if (check(mid)) res = min(res , mid) , r = mid - 1; else l = mid + 1; } return res; } int main() { scanf("%d" , &T); getmu(); while (T--) { scanf("%d" , &k); printf("%d\n" , slove()); } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具