P6583 回首过去 Sol

题目链接

依旧不会数论喵。只会 \(O(n^2\log n)\),被小 Z 打爆了啊。

考虑如何判定,显然有 \(y = 2^p5^q\times \gcd{(x,y)}\)。此时为 40pts,不如小 Z。

考虑变成 \(O(n)\),尝试通过枚举 \(y\) 实现。不难发现 \(x\) 只要是 \(y\) 除去因数 25 后的倍数就好了。这样子就能做到 \(O(n)\)

写出答案的表达式,为 \(\sum\limits_{i=1}^n \lfloor{n/f(i)}\rfloor\),其中 \(f(i)\) 定义为 \(i\) 除去因数 25 后的值。

看到这个,我们很想整除分块。不妨变成枚举 \(f(i)\)。则有答案为 \(\sum\limits_{k=1}^n \lfloor {n/k} \rfloor \times [2 \nmid k] \times [5 \nmid k] \times count(\lfloor {n/k} \rfloor)\)。这里 \(count(x)\) 表示在 \([1,x]\) 范围内,有多少值能记作 \(2^p5^q\)

做完了,我的做法是带 \(\log\) 的。

Code

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define File(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout)
#define LL long long
#define fi first
#define se second
LL n;
LL calc(LL x){
	return x - x / 5 - x / 2 + x / 10;
}
LL count(LL x){
	LL pow2;
	pow2 = 1;
	LL res = 0;
	for(pow2=1;pow2<=x;pow2 *= 2ll){
		for(LL pow5 = 1;pow5<=x;pow5 *= 5ll){
			if(pow2 * pow5 > x) break;
			res ++ ;
		}
	}
	return res;
}
int main(){
	IOS;
	cin >> n;
	LL ans = 0;
	for(LL l=1,r;l<=n;l=r+1){
		r = n / (n / l);
		ans += (calc(r) - calc(l-1)) * (n / l) * count(n / l);
	}
	cout << ans;
	return 0;
}
posted @ 2026-05-21 21:24  WinterXorSnow  阅读(12)  评论(0)    收藏  举报