BZOJ 2440 完全平方数(莫比乌斯反演+二分查找)

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=23362

题意:定义含有平方数因子的数为完全平方数(平方数因子不包含1)。求第k个非完全平方数。

思路:我们先求出[1, n]的非完全平方数的个数,然后利用二分来查找正好等于k时的n(注意这样的n可能不止一个,求最左边的)。关键是,怎么求出前者,我们可以利用容斥原理,用n - [1, n]内完全平方数的个数,求[1, n]内完全平方数的个数,用容斥发现前面的系数就是莫比乌斯函数,直接用莫比乌斯反演即可,结果为sigma(mu[i]*(n/(i*i)))。

code:

 1 #include <cstdio>
 2 #include <cstring>
 3 using namespace std;
 4 
 5 typedef long long LL;
 6 
 7 const LL INF = 2e10 + 7;
 8 const int MAXN = 100005;
 9 
10 bool check[MAXN];
11 int primes[MAXN];
12 int mu[MAXN];
13 LL k;
14 
15 void moblus()
16 {
17     memset(check, false, sizeof(check));
18     mu[1] = 1;
19     int cnt = 0;
20     for (int i = 2; i < MAXN; ++i) {
21         if (!check[i]) {
22             primes[cnt++] = i;
23             mu[i] = -1;
24         }
25         for (int j = 0; j < cnt; ++j) {
26             if (i * primes[j] > MAXN) break;
27             check[i * primes[j]] = true;
28             if (i % primes[j] == 0) {
29                 mu[i * primes[j]] = 0;
30                 break;
31             } else {
32                 mu[i * primes[j]] = -mu[i];
33             }
34         }
35     }
36 }
37 
38 LL cal(LL n)
39 {
40     LL ret = n;
41     for (LL i = 2; i * i <= n; ++i) {
42         ret += mu[i] * (n / (i * i));
43     }
44     return ret;
45 }
46 
47 int main()
48 {
49     moblus();
50     int nCase;
51     scanf("%d", &nCase);
52     while (nCase--) {
53         scanf("%lld", &k);
54         LL lhs = 1L;
55         LL rhs = INF;
56         LL mid;
57         while (lhs < rhs) {
58             mid = (rhs + lhs) / 2;
59             LL tmp = cal(mid);
60             if (tmp < k) lhs = mid + 1;
61             else rhs = mid;
62         }
63         printf("%lld\n", lhs);
64     }
65     return 0;
66 }

 

posted @ 2015-09-09 11:17  jasaiq  阅读(492)  评论(0编辑  收藏  举报