P6583 回首过去 题解
不错的 Idea。当然如果熟练莫反就是另一回事,但我不熟练(
注意到如果最简分数 是有限小数,那么 只能含有 2,5 这两个质因子(当然可以为 1)。
然而分数并不一定最简,所以考虑将分数变成 这个形式,其中保证 最简, 只含有 2,5 这两个质因子(或者为 1), 任意, 不能含有 2,5 这两个质因子。
显然合法的小于等于 的 可以预处理,因此考虑枚举 ,注意到枚举 时 限制过大不好化简,只能枚举出符合条件的 二元组的个数(人话:只能做到 ,可以自己手玩一下),因此考虑枚举 ,此时 ,然后由于 只含有 2,5 这两个质因子,所以个数是很少的,又因为 递增时 递减,所以是单调的,能做到 (实际上枚举 也是利用这一点)。
注意到 因此猜想应该是个根号算法,考虑令 表示当前枚举 时合法的 的个数,那么最终答案如下:
发现这是个整除分块的形式,但讨厌的是限制条件 ,考虑去掉这个限制条件,整除分块过程中处理出一段 相同的区间 后,考虑计算这个区间内满足限制条件的 的个数 ,这个可以简单容斥,, 表示 内 的倍数的个数,处理出 后整个区间的贡献就是 。
Code:
/*
========= Plozia =========
Author:Plozia
Problem:P6583 回首过去
Date:2022/10/20
========= Plozia =========
*/
#include <bits/stdc++.h>
typedef long long LL;
const int MAXN = 1e6 + 5;
LL n, a[MAXN], cnta;
LL Read()
{
LL sum = 0, fh = 1; char ch = getchar();
for (; ch < '0' || ch > '9'; ch = getchar()) fh -= (ch == '-') << 1;
for (; ch >= '0' && ch <= '9'; ch = getchar()) sum = (sum << 3) + (sum << 1) + (ch ^ 48);
return sum * fh;
}
LL Min(LL fir, LL sec) { return (fir < sec) ? fir : sec; }
LL g(LL l, LL r, LL x) { return r / x - (l - 1) / x; }
int main()
{
n = Read(); for (LL i = 1; i <= n; i <<= 1) for (LL j = i; j <= n; j *= 5) a[++cnta] = j;
LL ans = 0; int p = cnta; std::sort(a + 1, a + cnta + 1);
for (LL l = 1, r; l <= n; l = r + 1)
{
if (n / l == 0) r = n; else r = Min(n / (n / l), n);
while (p > 0 && a[p] > n / l) --p;
ans += (g(l, r, 1) - g(l, r, 2) - g(l, r, 5) + g(l, r, 10)) * (n / l) * p;
}
printf("%lld\n", ans); return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具