洛谷 P4318 完全平方数 二分+容斥
首先我们可以二分答案。然后转变为判断 \(mid\) 以内不讨厌的数和 \(k\) 的关系。
\(mid\) 以内不讨厌的数= \(mid\) \(-\) \(mid\) 以内讨厌的数
对于讨厌的数我们可以枚举 \(i\),看 \(i^2\) 会造成多少个讨厌的数,显然是 \(\displaystyle \left \lfloor \frac{n}{i^2} \right \rfloor\)
然后我们发现会有重复枚举的(像 \(36\) 会被 \(2,3,6\) 都枚举到),需要乘上一个容斥系数 \(f[i]\).
\(f[i]\) 取决于 \(i\) 有多少个质因数,奇数个为 \(1\) ,偶数个为 \(-1\) 。
这很好理解,比如一个数 \(n\) ,会被有一个质因数的 \(i\) 枚举的时候加上,被有偶数个质因数的 \(i\) 枚举的时候会发现减多了,枚举有 \(3\) 个质因数的 \(i\) 时还得加回来...
#include<iostream>
#include<cstdio>
#define LL long long
using namespace std;
int T, tot;
LL n, k, ans, l, r, mid;
int zhi[100010], f[100010], vis[100010];
void YYCH()
{
for (int i = 2; i <= 100000; ++i)
{
if (!vis[i])zhi[++tot] = i;
for (int j = 1; j <= tot && i * zhi[j] <= 100000; ++j)
{
vis[i * zhi[j]] = 1;
if (!(i % zhi[j]))break;
}
}
}
void dfs(int x, int beg, int js)
{
f[x] = js & 1 ? 1 : -1; long long y;
for (int i = beg; i <= tot; ++i)
{
if ((y = (long long)x * zhi[i]) > 100000)break;
dfs(y, i + 1, js + 1);
}
}
int check(LL n)
{
LL res = 0;
for (int i = 2; (LL)i * i <= n; ++i)
if (f[i])res += f[i] * n / ((LL)i * i);
return n - res;
}
signed main()
{
YYCH(); dfs(1, 1, 0);
cin >> T;
while (T--)
{
scanf("%lld", &k); l = 1; r = k << 1;
while (l <= r)
{
mid = (l + r) >> 1;
if (check(mid) >= k)r = mid - 1, ans = mid;
else l = mid + 1;
}
printf("%lld\n", ans);
}
return 0;
}