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 }
心之所动 且就随缘去吧