BZOJ 2440 [中山市选2011]完全平方数 【莫比乌斯反演】
Description
小 X 自幼就很喜欢数。但奇怪的是,他十分讨厌完全平方数。他觉得这些
数看起来很令人难受。由此,他也讨厌所有是完全平方数的正整数倍的数。然而
这丝毫不影响他对其他数的热爱。
这天是小X的生日,小 W 想送一个数给他作为生日礼物。当然他不能送一
个小X讨厌的数。他列出了所有小X不讨厌的数,然后选取了第 K个数送给了
小X。小X很开心地收下了。
然而现在小 W 却记不起送给小X的是哪个数了。你能帮他一下吗?
Hint
对于 100%的数据有 1 ≤ Ki ≤ 10^9,T ≤ 50
Solution
题意:求x,使得∑ | μ[i] | ==k ( 1<= i <=n )
首先,根据 μ 函数的定义,对于一个自然数 i 的所有质因子中存在因子的指数大于2,μ [ i ]=0
转化一下条件的描述,若 i 中含有完全平方的因子,μ[ i ]=0
我们定义 F( x ) 为小于等于 x 的 μ[ i ] ! = 0 的 i 的个数
可以考虑一下从 x 中减去 μ[ i ] ==0 的 i 的个数
我们枚举一下因子 i,小于等于 x 的数中含 i 平方的数的个数显然 x/i^2
根据容斥,前面乘个系数 μ[ i ]
然后求个和,二分一下答案,复杂度大约是 O(n) 的预处理 + O( √n * log n )的单次访问
1 #include<map> 2 #include<cmath> 3 #include<ctime> 4 #include<queue> 5 #include<stack> 6 #include<cstdio> 7 #include<climits> 8 #include<iomanip> 9 #include<cstring> 10 #include<cstdlib> 11 #include<iostream> 12 #include<algorithm> 13 14 #define maxp 50000 15 #define set(a,b) memset(a,(b),sizeof(a)) 16 #define fr(i,a,b) for(ll i=(a),_end_=(b);i<=_end_;i++) 17 #define rf(i,b,a) for(ll i=(a),_end_=(b);i>=_end_;i--) 18 #define fe(i,a,b) for(int i=first[(b)],_end_=(a);i!=_end_;i=s[i].next) 19 #define fec(i,a,b) for(int &i=cur[(b)],_end_=(a);i!=_end_;i=s[i].next) 20 21 using namespace std; 22 23 typedef long long ll; 24 25 const ll up=2e9; 26 27 28 ll prime[maxp],pri[maxp],miu[maxp],tot=0; 29 ll ans,k; 30 int T; 31 32 void read() 33 { 34 #ifndef ONLINE_JUDGE 35 freopen("2440.in","r",stdin); 36 freopen("2440.out","w",stdout); 37 #endif 38 cin >> T ; 39 } 40 41 void write() 42 {} 43 44 void print() 45 { 46 cout << ans << endl ; 47 } 48 49 void get() 50 { 51 miu[1]=1; 52 fr(i,2,maxp){ 53 if( !prime[i] ) pri[++tot]=i,miu[i]=-1; 54 int j=1; 55 while( j<=tot && pri[j]*i<=maxp ){ 56 prime[pri[j]*i]=1; 57 if( i%pri[j]==0 ){ 58 miu[pri[i]*j]=0; 59 break; 60 } 61 miu[i*pri[j]]=-miu[i]; 62 j++; 63 } 64 } 65 } 66 67 ll calc(ll x) 68 { 69 ll res=0; 70 fr(i,1,sqrt(x)) 71 res+=(x/(i*i))*miu[i]; 72 return res; 73 } 74 75 void work() 76 { 77 get(); 78 while( T-- ){ 79 cin >> k ; 80 ll l=1,r=up,mid; 81 while( l<=r ){ 82 mid=(l+r)>>1; 83 if( calc(mid)>=k ) ans=mid,r=mid-1; 84 else l=mid+1; 85 } 86 print(); 87 } 88 } 89 90 int main() 91 { 92 read(); 93 work(); 94 write(); 95 return 0; 96 }