- 双倍经验:vijos1889天真的因数分解
- 思考如何计算1~x内的非完全平方数
- 容斥原理:1~x内的非完全平方数 = 所有的数 - 所有有一个质数平方因子的数(4,9,25……的倍数)+所有有两个质数平方因子的数(36,100,……的倍数)-……
- 然后枚举所有 i * i < x ,这些i是所有可能的充当平方因子的质数,然后发现容斥原理里的系数正好等于 mu[i] ,所以每个算其对答案的贡献就是 mu[ i ] * x / ( i* i )
- 这里的mu[i]是莫比乌斯函数
- 所以预处理莫比乌斯函数,就可以在根号x下解决了
- 然后二分答案寻找第k个非完全平方数
- 注意二分答案的时候不是直接取f(mid)==k的那个mid,因为mid本身不一定是非完全平方数
- 代码:
1 #include <bits/stdc++.h> 2 #define nmax 2000050 3 4 using namespace std; 5 typedef long long ll; 6 ll x; 7 int table[nmax]={0},pri[nmax],mu[nmax]; 8 int cp=-1; 9 10 void getmu(){ //算莫比乌斯函数 11 for (int i=2; i<nmax; i++) { 12 if( !table[i] ) { pri[++cp]=i; mu[i]=-1; } 13 for (int j=0; j<=cp; j++) { 14 ll t=pri[j]*i; 15 if(t>=nmax) break; 16 table[t]=1; 17 if(i%pri[j]==0) { mu[t]=0; break;} 18 mu[t]=mu[i]*(-1); 19 } 20 } 21 mu[1]=1; 22 } 23 24 ll f(ll a){ //算1~a之间的非完全平方数的数量(包括a) 25 ll ans=0; 26 for (ll i=1; i*i<=a; i++) ans+=mu[i]*a/(i*i); 27 return ans; 28 } 29 30 int main(){ 31 getmu(); 32 int t; 33 cin>>t; 34 while(t--){ 35 scanf("%lld",&x); 36 //二分答案(这里mid的那个值也要是非完全平方数才行) 37 ll l=x,r=3*x,mid,ans; 38 while(l<r) { 39 mid=(l+r)>>1; 40 ll t=f(mid); 41 if( t>=x ) { ans=mid; r=mid;} 42 else l=mid+1; 43 if(l==r) ans=l; 44 } 45 cout<<ans<<endl; 46 } 47 return 0; 48 }
转载于:https://www.cnblogs.com/jiecaoer/p/11474525.html