[luogu4318]完全平方数

首先,我们肯定要用到二分答案。

这道题目就是统计第kμ不是0的数,线性筛显然会炸飞的,但当二分出一个数而统计有多少个小于等于他的合法数时,就可以容斥一下,即:1^2的倍数都不合法,2^2的倍数都不合法……4^2的倍数已经通过2^2统计过且没有重复……6^2的倍数被3^2的倍数和2^2的倍数重复统计因此要加上……

对于如上过程,我们可以简化成一个公式:$\sum_{i=1}^{\sqrt{k}}\mu(i)\cdot k/i^{2}$,而i的范围是$\sqrt{k}=40000$,再乘上二分的$o(log_{2}n)$就可以过掉了(当然还可以对i进行数论分块,使得i的范围为200,但实际并不需要)。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define N 100005
 5 ll t,n,l,r,mid,ans,mu[N],vis[N],p[N];
 6 void mobies(int n){
 7     mu[1]=1;
 8     for(int i=2;i<=n;i++){
 9         if (!vis[i])mu[p[++p[0]]=i]=-1;
10         for(int j=1;j<=p[0];j++){
11             if (p[j]*i>n)break;
12             vis[i*p[j]]=1;
13             if (i%p[j]==0)break;
14             mu[i*p[j]]=-mu[i];
15         }
16     }
17 }
18 ll calc(ll n){
19     ll ans=0;
20     for(ll i=1;i*i<=n;i++)ans+=n/(i*i)*mu[i];
21     return ans;
22 }
23 int main(){
24     scanf("%lld",&t);
25     mobies(N-5);
26     while (t--){
27         scanf("%lld",&n);
28         for(l=1,r=(n<<1),mid=n;l<r;mid=(l+r>>1))
29             if (calc(mid)<n)l=mid+1;
30             else r=mid;
31         printf("%lld\n",l);
32     }
33 }
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/11272112.html