完全平方数(莫比乌斯函数容斥)

小 X 自幼就很喜欢数。但奇怪的是,他十分讨厌完全平方数。他觉得这些数看起来很令人难受。由此,他也讨厌所有是完全平方数的正整数倍的数。然而这丝毫不影响他对其他数的热爱。

这天是小X的生日,小 W 想送一个数给他作为生日礼物。当然他不能送一个小X讨厌的数。他列出了所有小X不讨厌的数,然后选取了第 K个数送给了小X。小X很开心地收下了。

然而现在小 W 却记不起送给小X的是哪个数了。你能帮他一下吗?

Solution

首先可以在外层套上二分答案把问题转化为判定问题。

问题变成了在1~x中,是否存在mid个数不是完全平方数。

根据容斥原理,答案就是:0个质数乘积的平方的倍数的数量(1的倍数)- 1个质数乘积的平方的倍数的数量(4,9,25的倍数)+ 2个质数乘积的平方的倍数的数量(36,100的倍数)。

再来分析一波莫比乌斯函数,当i中存在完全平方数时,miu[i]=0,有奇数个质因子时我们应当减一,有偶数个质因子时就加。

所以我们枚举i,容斥系数就是miu[i].

Code

#include<iostream>
#include<cstdio>
#include<cmath>
#define N 300009
using namespace std;
long long  miu[N],div[N],prime[N],n,t;
inline void kk()
{
    miu[1]=1;
    for(int i=2;i<=N;++i)
    {
        if(!div[i])
        {
            prime[++prime[0]]=i;
            miu[i]=-1;
        }
        for(int j=1;j<=prime[0]&&prime[j]*i<=N;++j)
        { 
          div[prime[j]*i]=1;
          if(i%prime[j]==0)
          {miu[i*prime[j]]=0;break;}
          else miu[i*prime[j]]=-miu[i];
        }
    }
}
long long find(long long x)
{
    long long ll=sqrt(x),ans=0;
    for(int i=1;i<=ll;++i)
      ans+=miu[i]*x/(i*i);
    return ans;
}
long long work(long long x)
{
    long long l=1,r=x<<1,ans=0;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(find(mid)<x)l=mid+1;
        else
        {
            ans=mid;r=mid-1;
        } 
    } 
    return ans;
}
int main()
{
    cin>>t;
    kk();
    while(t--)
    {
        scanf("%lld",&n);
        printf("%lld\n",work(n));
    }
    return 0;
}

 

posted @ 2018-10-09 16:43  comld  阅读(1084)  评论(0编辑  收藏  举报