反函数1 - 数论 - 杜教筛

题目大意:给定n,k,求满足miu(x)=n的第k小的x。k<=1e9。
题解:考虑令a,b,c表示1,0,-1的个数,二分答案,设为x,那么a+b+c=x,a+c= i = 1 n μ 2 ( i ) = i = 1 n n i 2 μ ( i ) , a c = i = 1 n μ ( i ) \sum_{i=1}^n\mu^2(i)=\sum_{i=1}^n\left\lfloor\frac n{i^2}\right\rfloor\mu(i),a-c=\sum_{i=1}^n\mu(i) ,最后一个杜教筛即可。

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lint long long
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
const int N=10000010;int v;lint iN;
bool np[N];int p[N],ms[N];
unordered_map<lint,lint> sav;
inline int prelude(int n)
{
    ms[1]=1;
    for(int i=2,c=0;i<=n;i++)
    {
        if(!np[i]) p[++c]=i,ms[i]=-1;
        rep(j,1,c&&p[j]<=n/i)
        {
            int x=p[j]*i;np[x]=1,ms[x]=-ms[i];
            if(i%p[j]==0) { ms[x]=0;break; }
        }
    }
    rep(i,2,n) ms[i]+=ms[i-1];
    return 0;
}
inline lint getz(lint n)
{
    if(n<N) return ms[n];
    if(sav.count(n)) return sav[n];
    lint ans=0;
    for(lint s=2,t;s<=n;s=t+1)
        t=n/(n/s),ans+=getz(n/s)*(t-s+1);
    return sav[n]=1-ans;
}
inline lint gety(lint n)
{
    lint ans=0;rep(i,1,n/i) ans+=n/i/i*(ms[i]-ms[i-1]);return ans;
}
inline lint check(lint x)
{
    lint y=gety(x),z=getz(x);
    if(v==0) return x-y;
    if(v==1) return (y+z)>>1;
    return (y-z)>>1;
}
int main()
{
    lint k;cin>>v>>k;prelude(N-1);
    lint L=1,R=5e9,mid=(L+R)>>1;
    while(L<=R)
    {
        if(check(mid)>=k) R=mid-1;
        else L=mid+1;mid=(L+R)>>1;
    }
    cout<<L<<endl;return 0;
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/84727354
今日推荐