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

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

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

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

容斥+莫比乌斯函数


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

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

SP4168 SQFREE - Square-free integers

现在考虑原问题的逆问题,即 \([1,\ n]\) 中是完全平方数的正整数倍的数的个数,由容斥原理得到 $$\lfloor\frac{n}{22}\rfloor+\lfloor\frac{n}{32}\rfloor+\lfloor\frac{n}{52}\rfloor-\lfloor\frac{n}{62}\rfloor+\lfloor\frac{n}{72}\rfloor-\lfloor\frac{n}{102}\rfloor+\cdots$$

\(\therefore\) 原式 \(=\) $$n-\lfloor\frac{n}{22}\rfloor-\lfloor\frac{n}{32}\rfloor-\lfloor\frac{n}{52}\rfloor+\lfloor\frac{n}{62}\rfloor-\lfloor\frac{n}{72}\rfloor+\lfloor\frac{n}{102}\rfloor+\cdots$$

现在观察 \(\lfloor\frac{n}{i^2}\rfloor\) 的系数:$$1\times n+(-1)\times\lfloor\frac{n}{22}\rfloor+(-1)\times\lfloor\frac{n}{32}\rfloor+0\times\lfloor\frac{n}{42}\rfloor+(-1)\times\lfloor\frac{n}{52}\rfloor+1\times\lfloor\frac{n}{62}\rfloor+(-1)\times\lfloor\frac{n}{72}\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\sqrt k\log 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;
}
posted @ 2019-01-31 13:34  cnJuanzhang  阅读(116)  评论(0编辑  收藏  举报