BZOJ 2440: [中山市选2011]完全平方数 莫比乌斯函数 容斥原理 二分答案

先二分答案,check(x)表示[1,x]的数中,不是完全平方数整数倍数的数的个数。第一个check(x)为Ki的数x即为答案。

考虑如何求出check(x)。我们考虑通过容斥原理,去从x中删掉为平方数整数倍数的数的个数。

所以res = x - (单个素数的平方的整数倍的数)+(两个素数乘积的平方的整数倍的数)-(三个素数乘积的平方的整数倍的数)……

而可能是[1,x]的完全平方数整数倍数的中的因子(素数或素数乘积),显然不超过sqrt(x)。所以只考虑[1,sqrt(x)]中的素数(或乘积)即可。

我们考虑μ(a),如果a含有平方数因子,即μ(a) = 0,a显然不是素数成绩,a不位于上式中,a及其倍数显然不对答案产生贡献。如果a不含有平方数因子,即μ(a) = (-1)^k。则如果k为奇数,那么μ(a)=-1。可以注意到,a及其倍数会在(k个素数乘积的平方的整数倍的数)中出现,系数为-1。而当k为偶数时,同理。所以μ(a)即为a的平方及其倍数的系数。而x内有x / (a * a)个a^2的倍数。

 

 1 #include <cstdio>
 2 #include <cmath>
 3 #include <vector>
 4 using namespace std;
 5 typedef long long ll;
 6 vector <int> vec;
 7 bool vis[101000];
 8 int mu[101000];
 9 void mobius(int n)
10 {
11     mu[1] = 1;
12     for (int i = 2;i <= n;i++)
13     {
14         if (vis[i] == false)
15         {
16             vec.push_back(i);
17             mu[i] = -1;
18         }
19         for (int j = 0;j < vec.size() && i * vec[j] <= n;j++)
20         {
21             vis[i * vec[j]] = true;
22             if (i % vec[j] == 0)
23             {
24                 mu[i * vec[j]] = 0;
25                 break;
26             }
27             mu[i * vec[j]] = -mu[i];
28         }
29     }
30 }
31 ll check(ll x)
32 {
33     ll tp = sqrt(x),res = 0;
34     for (int i = 1;i <= tp;i++)
35         res += mu[i] * (x / i / i);
36     return res;
37 }
38 int T,n;
39 int main()
40 {
41     mobius(100000);
42     for (scanf("%d",&T);T;T--)
43     {
44         scanf("%d",&n);
45         ll l = 1,r = (1ll << 31) - 1,mid;
46         while (l < r)
47         {
48             mid = l + r >> 1;
49             if (check(mid) >= n)
50                 r = mid;
51             else
52                 l = mid + 1;
53         }
54         printf("%lld\n",l);
55     }
56 }

 

posted @ 2019-02-22 16:15  IAT14  阅读(175)  评论(0编辑  收藏  举报