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

Description

小 X 自幼就很喜欢数。但奇怪的是,他十分讨厌完全平方数。他觉得这些数看起来很令人难受。由此,他也讨厌所有是完全平方数的正整数倍的数。然而这丝毫不影响他对其他数的热爱。
这天是小X的生日,小 W 想送一个数给他作为生日礼物。当然他不能送一个小X讨厌的数。他列出了所有小X不讨厌的数,然后选取了第 K个数送给了小X。小X很开心地收下了。
然而现在小 W 却记不起送给小X的是哪个数了。你能帮他一下吗?

Input

包含多组测试数据。文件第一行有一个整数 T,表示测试数据的组数。
第2 至第T+1 行每行有一个整数Ki,描述一组数据,含义如题目中所描述。 

Output

含T 行,分别对每组数据作出回答。第 i 行输出相应的第Ki 个不是完全平方数的正整数倍的数。

Sample Input

4
1
13
100
1234567

Sample Output

1
19
163
2030745

HINT

对于 100%的数据有 1 ≤ Ki ≤ 10^9,  T ≤ 50

题解

既然要求没有平方因子,等价于这个数唯一分解后素因数次数均为 1 。显然就是求 $\mu\neq 0$ 的第 $K$ 个值。

然而 $K\leq 10^9$ 是存不下的。我们换一个思路。

我们试着枚举每个不含平方因子的数 $i$ 用容斥原理筛出。值得注意的是有贼有意思的事情:由莫比乌斯函数的定义,我们可以确定在 $N$ 内的满足题意的数的个数为 $$ans=N+\sum_{i=2}^{\sqrt N}\mu(i)\left\lfloor\frac{N}{i^2}\right\rfloor$$

所以二分答案,再 $O(\sqrt N)$ 检验即可。

 1 //It is made by Awson on 2018.1.23
 2 #include <set>
 3 #include <map>
 4 #include <cmath>
 5 #include <ctime>
 6 #include <queue>
 7 #include <stack>
 8 #include <cstdio>
 9 #include <string>
10 #include <vector>
11 #include <cstdlib>
12 #include <cstring>
13 #include <iostream>
14 #include <algorithm>
15 #define LL long long
16 #define Abs(a) ((a) < 0 ? (-(a)) : (a))
17 #define Max(a, b) ((a) > (b) ? (a) : (b))
18 #define Min(a, b) ((a) < (b) ? (a) : (b))
19 #define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
20 #define writeln(x) (write(x), putchar('\n'))
21 #define lowbit(x) ((x)&(-(x)))
22 using namespace std;
23 const int K = 1e9;
24 const int N = 1e5;
25 void read(int &x) {
26     char ch; bool flag = 0;
27     for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
28     for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
29     x *= 1-2*flag;
30 }
31 void write(LL x) {
32     if (x > 9) write(x/10);
33     putchar(x%10+48);
34 }
35 
36 int n, m, mu[N+5];
37 int isprime[N+5], prime[N+5], tot;
38 
39 void get_mu() {
40     memset(isprime, 1, sizeof(isprime)); isprime[1] = 0, mu[1] = 1;
41     for (int i = 2; i <= N; i++) {
42     if (isprime[i]) prime[++tot] = i, mu[i] = -1;
43     for (int j = 1; j <= tot && i*prime[j] <= N; j++) {
44         isprime[i*prime[j]] = 0;
45         if (i%prime[j]) mu[i*prime[j]] = -mu[i];
46         else {mu[i*prime[j]] = 0; break; }
47     }
48     }
49 }
50 int cal(int m, int k) {
51     int n = sqrt(m); LL ans = m;
52     for (int i = 2; i <= n; i++) ans += (LL)mu[i]*(m/i/i);
53     return ans >= k;
54 }
55 void work() {
56     read(n); int L = 1, R = n<<1, ans = n;
57     while (L <= R) {
58     int mid = ((LL)L+R)>>1;
59     if (cal(mid, n)) ans = mid, R = mid-1;
60     else L = mid+1;
61     }
62     writeln(ans);
63 }
64 int main() {
65     int t; read(t); get_mu();
66     while (t--) work();
67     return 0;
68 }

 

posted @ 2018-01-25 16:42  NaVi_Awson  阅读(151)  评论(0编辑  收藏  举报