bzoj 2440 (莫比乌斯函数)
题意:找出第k个不是完全平方数的正整数倍的数。
例如 4 9 16 25 36什么的
通过容斥原理,我们减去所有完全数 4有n/4个,但是36这种会被重复减去,
所有我们还需要加上类似36的数,然后你会发现这些数前面的符号和他们开根号的
莫比乌斯函数一样
数据很大有1e9,如果先进行预处理再从头到尾找感觉不现实,考虑使用二分,枚举mid,
然后每次查找1到mid中不是完全平方数的正整数倍的数的个数
Orz:机制的二分使用
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <queue> #include <vector> #include <algorithm> #include <functional> typedef long long ll; using namespace std; const int inf = 0x3f3f3f3f; const int maxn = 1e5; int tot; int is_prime[maxn]; int mu[maxn]; int prime[maxn]; void Moblus() { tot = 0; mu[1] = 1; for(int i = 2; i < maxn; i++) { if(!is_prime[i]) { prime[tot++] = i; mu[i] = -1; } for(int j = 0; j < tot && i*prime[j] < maxn; j++) { is_prime[i*prime[j]] = 1; if(i % prime[j]) { mu[i*prime[j]] = -mu[i]; } else { mu[i*prime[j]] = 0; break; } } } } ll get_(ll mid) { ll num = 0; for(int i = 1; i*i <= mid; i++) { num += (ll)mu[i]*(mid/(i*i)); } return num; } int main() { int T; Moblus(); scanf("%d",&T); while(T--) { ll k; scanf("%lld",&k); ll l = 1; ll r = 2*k+1; while(l <= r) { ll mid = (l+r)>>1; ll num = get_(mid); if(num < k) l = mid + 1; else r = mid - 1; } printf("%lld\n",l); } }