完全平方数 HYSBZ - 2440【莫比乌斯函数+二分】

题意:

求出第 \(ki\) 个不是完全平方数的整数倍的数。(\(1\) 是第一个)
数据范围:\(1 ≤ Ki ≤ 10^9,T ≤ 50\)

分析:

首先可以想到,用容斥定理来求。但实际上,完全平方数有很多,不可能一个一个地枚举出来,然后奇加偶减。
对于 \(\sqrt{n}\) 以内的素数集合:\(s\)\(n\) 以内的不含完全平方数因子的数的个数:
\(ans=\frac{n}{1*1}-\frac{n}{2*2}-\frac{n}{3*3}-\frac{n}{5*5}+\frac{n}{6*6}...\)
显然,偶数个质数平方对于答案的贡献就是正的,否则是负;如果不是若干个互异质数的乘积,那么对答案没有影响,因为它们已经被所含的质数处理过。
所以:

\[ans=\sum_{i=1}^{\sqrt{n}}{mu[i]*\frac{n}{i*i}} \]

结合二分即可找出符合条件的数。
注意
1.二分时,是找到第一个满足条件的数,所以在改变区间时要注意写法;
2.二分时,\(l+r\) 会爆 \(int\)

代码:

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
const int N=1e5+5;
int mu[N];
vector<int>prime;
bool vis[N];
void read(int &x)
{
    x=0;
    int f=1;
    char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(isdigit(ch))
    {
        x=(x<<3)+(x<<1)+ch-'0';
        ch=getchar();
    }
    x*=f;
}
void init()
{
    mu[1]=1;
    memset(vis,0,sizeof(vis));
    for(int i=2;i<=N-5;i++)
    {
        if(!vis[i])
        {
            prime.pb(i);
            mu[i]=-1;
        }
        for(int j=0;j<prime.size()&&1LL*prime[j]*i<=N-5;j++)
        {
            vis[i*prime[j]]=1;
            if(i%prime[j]==0)
            {
                mu[i*prime[j]]=0;
                break;
            }
            else
                mu[i*prime[j]]=-mu[i];
        }
    }
}
ll solve(int n)
{
    ll ans=0;
    for(int i=1;1LL*i*i<=n;i++)
        ans+=(mu[i]*n/(i*i));
    return ans;
}
int main()
{
    int t,k;
    init();
    read(t);
    while(t--)
    {
        read(k);
        ll l=1,r=2*k+5;
        while(l<=r)
        {
            ll mid=(l+r)>>1;
            ll t=solve(mid);
            if(t<k)
                l=mid+1;
            else
                r=mid-1;
        }
        printf("%lld\n",l);
    }
    return 0;
}

posted @ 2020-03-21 10:55  xzx9  阅读(178)  评论(0编辑  收藏  举报