洛谷P4318 完全平方数
标签
- 莫比乌斯反演
- 二分答案
前言
简明题意
- 给定 k k k,需要你求出从1开始第 k k k个不含平方因子的数。
思路
- 首先,很容易想到莫比乌斯函数,当 i i i有平方因子, μ ( i ) = 0 \mu(i)=0 μ(i)=0; i i i没有平方因子,则 μ ( i ) = ± 1 \mu(i)=\pm1 μ(i)=±1。我们先把莫比乌斯函数筛出来,然后预处理一下:第 i i i个不含平方因子的数是多少。然后,对于每组询问 O ( 1 ) O(1) O(1)查询就好了。但是这样复杂度是 O ( n ) O(n) O(n),最多只能处理到1e7,最后能得到70分。
- 接下来我们优化。正解是二分答案。显然一个数越大,它前面的不含平方因子的数越多。因此我们二分所有的数,当这个数前面的不含平方因子的数多于给定的k,我们就缩小,否则增大。然后问题就在于check函数,如何求出给定n,[1,n]范围内不含平方因子的数的个数。
- f ( x ) = ∑ i = 1 [ s q r t ( x ) ] μ ( i ) ∗ [ x i 2 ] f(x)=\sum\limits_{i=1}^{[sqrt(x)]}\mu(i)*[\frac{x}{i^2}] f(x)=i=1∑[sqrt(x)]μ(i)∗[i2x],就是[1,x]范围内,不含平方因子的数的数量。(具体怎么推的我也没懂)
注意事项
- 无
总结
- [1,x]范围内,不含平方因子的数的数量是: f ( x ) = ∑ i = 1 [ s q r t ( x ) ] μ ( i ) ∗ [ x i 2 ] f(x)=\sum\limits_{i=1}^{[sqrt(x)]}\mu(i)*[\frac{x}{i^2}] f(x)=i=1∑[sqrt(x)]μ(i)∗[i2x]
AC代码
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 1e7 + 10;
bool no_prime[maxn];
int prime[maxn], mu[maxn], pre[maxn];
int shai(int n)
{
int cnt = 0;
mu[1] = 1;
for (int i = 2; i <= n; i++)
{
if (!no_prime[i])
prime[++cnt] = i, mu[i] = -1;
for (int j = 1; j <= cnt && prime[j] * i <= n; j++)
{
no_prime[prime[j] * i] = 1;
mu[prime[j] * i] = i % prime[j] == 0 ? 0 : -mu[i];
if (i % prime[j] == 0) break;
}
}
for (int i = 1; i <= n; i++)
pre[i] += pre[i - 1] + mu[i];
return cnt;
}
long long cal(int n)
{
long long l = 1, r, ans = 0;
while (l <= n)
{
r = n / (n / l);
ans += (n / l) * (pre[r] - pre[l - 1]);
l = r + 1;
}
return ans;
}
int k;
bool check(long long x)//
{
long long sum = 0;
for (long long i = 1; i * i <= x; i++)
sum += mu[i] * (x / (i * i));
return sum >= k;
}
void solve()
{
shai(maxn - 10);
int t;
scanf("%d", &t);
while (t--)
{
scanf("%d", &k);
long long l = 1, r = 1e10, ans;
while (l <= r)
{
long long mid = (l + r) / 2;
if (check(mid))
r = mid - 1, ans = mid;
else
l = mid + 1;
}
printf("%lld\n", ans);
}
}
int main()
{
freopen("Testin.txt", "r", stdin);
solve();
return 0;
}