题意

求自然数中,第\(k\)个不含平方因子的数

思路

这道题的做法还挺多的(打表,二分,反演...)

我用的做法是二分+容斥

显然答案满足二分性,假设当前检验的数为\(n\)

没有平方因子的数=所有数-一个质数平方的因子的倍数+两个质数乘积平方的倍数-三个的.......

对于一个数\(i^2\),可以发现\(\mu (i)\)就是\(i^2\)在上面那个式子中的系数,所以上式可以表示为\[ans=\sum_{i=1}^{i^2\leq n}{\mu (i)\times \frac{n}{i^2}}\]

一遍\(check\)\(\sqrt {n}\),所以整个算法复杂度为\(O(logn\sqrt {n})\)

Code

#include<bits/stdc++.h>
#define N 50005
using namespace std;
typedef long long ll;
int T;
int p[N],mu[N],cnt;
ll k;
bool isnotp[N];

template <class T>
void read(T &x)
{
    char c;int sign=1;
    while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
    while((c=getchar())>='0'&&c<='9') x=x*10+c-48; x*=sign;
}

void init(int maxn)
{
    isnotp[1]=1;
    mu[1]=1;
    for(int i=2;i<=maxn;++i)
    {
        if(!isnotp[i]) p[++cnt]=i,mu[i]=-1;
        for(int j=1;j<=cnt&&(ll)p[j]*i<=maxn;++j)
        {
            isnotp[p[j]*i]=1;
            if(i%p[j]==0)
            {
                mu[i*p[j]]=0;
                break;
            }
            else mu[i*p[j]]=-mu[i];
        }
    }
}
bool check(ll x)//[1,x]>=k ?
{
    ll ret=0;
    for(ll i=1;i*i<=x;++i) ret+=mu[i]*(x/(i*i));
    return ret>=k;
}

int main()
{
    read(T);
    init(N-5);
    while(T--)
    {
        ll l=1,r=5000000000LL,ans=0;
        read(k);
        while(l<=r)
        {
            ll mid=(l+r)>>1;
            if(check(mid)) r=mid-1,ans=mid;
            else l=mid+1;
        }
        printf("%lld\n",ans);
    }
    return 0;
}
12-28 20:51