bzoj2440 [中山市选2011]完全平方数

\(\verb|bzoj2440 [中山市选2011]完全平方数|\)

求第 \(k\) 个不是完全平方数的正整数倍的数,\(T\) 组询问

\(T\leq50,\ k\leq10^9\)

容斥+莫比乌斯函数


首先二分,将原问题转化为

\([1,\ n]\) 中不是完全平方数的正整数倍的数的个数

\(\verb|SP4168 SQFREE - Square-free integers|\)

现在考虑原问题的逆问题,即 \([1,\ n]\) 中是完全平方数的正整数倍的数的个数,由容斥原理得到 \[\lfloor\frac{n}{2^2}\rfloor+\lfloor\frac{n}{3^2}\rfloor+\lfloor\frac{n}{5^2}\rfloor-\lfloor\frac{n}{6^2}\rfloor+\lfloor\frac{n}{7^2}\rfloor-\lfloor\frac{n}{10^2}\rfloor+\cdots\]

\(\therefore\) 原式 \(=\) \[n-\lfloor\frac{n}{2^2}\rfloor-\lfloor\frac{n}{3^2}\rfloor-\lfloor\frac{n}{5^2}\rfloor+\lfloor\frac{n}{6^2}\rfloor-\lfloor\frac{n}{7^2}\rfloor+\lfloor\frac{n}{10^2}\rfloor+\cdots\]

现在观察 \(\lfloor\frac{n}{i^2}\rfloor\) 的系数:\[1\times n+(-1)\times\lfloor\frac{n}{2^2}\rfloor+(-1)\times\lfloor\frac{n}{3^2}\rfloor+0\times\lfloor\frac{n}{4^2}\rfloor+(-1)\times\lfloor\frac{n}{5^2}\rfloor+1\times\lfloor\frac{n}{6^2}\rfloor+(-1)\times\lfloor\frac{n}{7^2}\rfloor+0\times\lfloor\frac{n}{8^2}\rfloor+\cdots\]

有没有想到那个熟悉的函数 \[\mu(i)=\begin{cases}1&&(i=1)\\(-1)^k&&(i=\prod p_k,\ p_k\in prime)\\0&&other\end{cases}\]

易证原式 \(\lfloor\frac{n}{i^2}\rfloor\) 的系数即为 \(\mu(i)\)

即求 \[\displaystyle\sum_{i=1}^\sqrt n \mu(i)\lfloor\frac{n}{i^2}\rfloor\]

可以发现最终答案 \(ans\) 满足 \(k\le ans\leq 2\times k\)

因此时间复杂度 \(O(T\log k\sqrt k)\),空间复杂度 \(O(\sqrt k)\)

代码

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 5e4 + 10;
int T, n, tot, p[maxn], mu[maxn];

void sieve() {
  int t = 45000; mu[1] = 1;
  for (int i = 2; i <= t; i++) {
    if (!p[i]) mu[i] = -1, p[++tot] = i;
    for (int j = 1; j <= tot && i * p[j] <= t; j++) {
      p[i * p[j]] = 1;
      if (i % p[j] == 0) {
        mu[i * p[j]] = 0; break;
      }
      mu[i * p[j]] = -mu[i];
    }
  }
}

bool check(int x) {
  int t = sqrt(x), res = x;
  for (int i = 2; i <= t; i++) {
    res += x / (i * i) * mu[i];
  }
  return res < n;
}

int main() {
  scanf("%d", &T), sieve();
  while (T--) {
    scanf("%d", &n);
    ll l = n, r = n << 1, mid, res;
    while (l <= r) {
      check(mid = (l + r) >> 1) ? l = mid + 1 : r = (res = mid) - 1;
    }
    printf("%d\n", (int)res);
  }
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/Juanzhang/p/10341603.html
今日推荐