[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
1
13
100
1234567
Sample Output
1
19
163
2030745
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 }
博主蒟蒻,随意转载。但必须附上原文链接:http://www.cnblogs.com/NaVi-Awson/,否则你会终生找不到妹子!!!