P6583 回首过去 Sol
依旧不会数论喵。只会 \(O(n^2\log n)\),被小 Z 打爆了啊。
考虑如何判定,显然有 \(y = 2^p5^q\times \gcd{(x,y)}\)。此时为 40pts,不如小 Z。
考虑变成 \(O(n)\),尝试通过枚举 \(y\) 实现。不难发现 \(x\) 只要是 \(y\) 除去因数 2,5 后的倍数就好了。这样子就能做到 \(O(n)\)。
写出答案的表达式,为 \(\sum\limits_{i=1}^n \lfloor{n/f(i)}\rfloor\),其中 \(f(i)\) 定义为 \(i\) 除去因数 2、5 后的值。
看到这个,我们很想整除分块。不妨变成枚举 \(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;
}

浙公网安备 33010602011771号