题意
T T T 组询问,回答第 K i K_i Ki 个不是完全平方数的正整数倍的数。
1 ≤ K i ≤ 1 0 9 , T ≤ 50 1\le K_i \le 10^9,T \le 50 1≤Ki≤109,T≤50
分析:
法一:
如果一个数 n n n 不是完全平方数,那么 n = p 1 α 1 p 2 α 2 ⋯ p k α k n=p_1^{\alpha_1}p_2^{\alpha_2} \cdots p_k^{\alpha_k} n=p1α1p2α2⋯pkαk 中 0 ≤ α i ≤ 1 0 \le \alpha_i \le 1 0≤αi≤1,所以就想到了莫比乌斯函数,那么题目要询问第 K K K 个数是什么,可以用二分来解决,但是必须要有单调性,莫比乌斯函数前缀和可能存在负数,所以就想到把莫比乌斯函数做一个平方,这样前缀和就没有负数了,就有了单调性。
现在考虑如何计算 ∑ i = 1 n μ 2 ( i ) \sum\limits_{i=1} ^{n} \mu^2(i) i=1∑nμ2(i),根据数据范围来看必须要用杜教筛来快速求前缀和,设 f ( n ) = μ 2 ( n ) f(n)=\mu^2(n) f(n)=μ2(n),那么设 g ( n ) = [ n = k 2 , k ∈ N + ] g(n)=[n=k ^ 2,k \in N^+] g(n)=[n=k2,k∈N+],发现 f ∗ g = 1 f*g=1 f∗g=1,所以
S ( n ) = n − ∑ i = 2 n g ( i ) S ( ⌊ n i ⌋ ) S(n)=n-\sum_{i=2}^{n}g(i)S(\lfloor \frac{n}{i} \rfloor) S(n)=n−i=2∑ng(i)S(⌊in⌋)
改为枚举平方
S ( n ) = n − ∑ i = 2 n S ( ⌊ n i 2 ⌋ ) S(n)=n-\sum_{i=2}^{\sqrt{n}}S(\lfloor \frac{n}{i^2} \rfloor) S(n)=n−i=2∑nS(⌊i2n⌋)
代码( O 2 O_2 O2优化):
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e6 + 5;
unordered_map<int,int> mp;
int T, n, mobius[N], primes[N], cnt, sum[N];
bool st[N];
void get_mobius(int n) {
mobius[1] = 1;
for (int i = 2; i <= n; i ++) {
if (!st[i]) {
primes[cnt ++] = i;
mobius[i] = -1;
}
for (int j = 0; primes[j] * i <= n; j ++) {
int t = primes[j] * i;
st[t] = 1;
if (i % primes[j] == 0) {
mobius[t] = 0;
break;
}
mobius[t] = -mobius[i];
}
}
for (int i = 1; i <= n; i ++) sum[i] = sum[i - 1] + mobius[i] * mobius[i];
}
int Sum(int n) {
if (n < N) return sum[n];
if (mp[n]) return mp[n];
int res = n;
for (int l = 2, r; l * l <= n; l = r + 1) {
r = n / (n / l);
res -= Sum(n / (l * l));
}
return mp[n] = res;
}
signed main() {
get_mobius(N - 1);
cin >> T;
while (T --) {
cin >> n;
int l = 1, r = n << 1;
while (l < r) {
int mid = l + r >> 1;
if (Sum(mid) < n) {
l = mid + 1;
} else {
r = mid;
}
}
cout << l << endl;
}
}
法二:
∑ i = 1 n μ 2 ( i ) = ∑ i = 1 n ∑ d 2 ∣ i μ ( d ) = ∑ d = 1 n μ ( d ) ⌊ n d 2 ⌋ \sum_{i=1}^{n} \mu^2(i)=\sum_{i=1} ^{n}\sum_{d^2 \mid i} \mu(d)=\sum_{d=1} ^{\sqrt{n}} \mu(d)\lfloor \frac{n}{d^2}\rfloor i=1∑nμ2(i)=i=1∑nd2∣i∑μ(d)=d=1∑nμ(d)⌊d2n⌋
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e6 + 5;
int T, n, mobius[N], primes[N], cnt, sum[N];
bool st[N];
void get_mobius(int n) {
mobius[1] = 1;
for (int i = 2; i <= n; i ++) {
if (!st[i]) {
primes[cnt ++] = i;
mobius[i] = -1;
}
for (int j = 0; primes[j] * i <= n; j ++) {
int t = primes[j] * i;
st[t] = 1;
if (i % primes[j] == 0) {
mobius[t] = 0;
break;
}
mobius[t] = -mobius[i];
}
}
for (int i = 1; i <= n; i ++) sum[i] = sum[i - 1] + mobius[i];
}
int Sum(int n) {
int res = 0;
for (int l = 1, r; l * l <= n; l = r + 1) {
r = n / (n / l);
res += (sum[r] - sum[l - 1]) * (n / (l * l));
}
return res;
}
signed main() {
get_mobius(N - 1);
cin >> T;
while (T --) {
cin >> n;
int l = 1, r = n << 1;
while (l < r) {
int mid = l + r >> 1;
if (Sum(mid) < n) {
l = mid + 1;
} else {
r = mid;
}
}
cout << l << endl;
}
}