T^TOJ - 2360 - Home_W的超级数学题 - 莫比乌斯反演 - 质因数分解

求单个莫比乌斯函数忘记算n本身的质数,WA了一发。

http://www.fjutacm.com/Problem.jsp?pid=2360

首先,显然随着n增大,与m互质的数不会变少。可以二分来求k,关键是怎么快速计算n以内和m互质的数的个数。

反过来,我们求n以内与m的gcd至少为2的数的个数。

枚举m的因子d,d从2开始到m,那么每个因子d的贡献就是mu(d),不知道怎么解释好。
比如枚举了gcd为因子2,那么gcd为4,8的情况就已经被2包含了,不用计算,直接mu(4)=mu(8)=0。
又比如gcd为10的被2和5分别枚举一次,根据容斥原理就要变成-1,mu(10)=-1。

那么就套上一个莫比乌斯的板子。

复杂度是什么呢?首先是二分k,有个log,上限取1e18大概弄60次。
对于每个n=mid,快速计算,枚举因子,1e9的因子貌似也就1e4以下?
每个因子的莫比乌斯函数是根号求出来的,运气好点就卡过去了。

#include<cstdio>
using namespace std;
typedef long long ll;

const int N=10025;

int pri[N+5],tot,zhi[N+5];
void sieve(int n) {
    zhi[1]=1;
    for(int i=2; i<=n; i++) {
        if(!zhi[i])
            pri[++tot]=i;
        for(int j=1; j<=tot&&i*pri[j]<=n; j++) {
            zhi[i*pri[j]]=1;
            if(i%pri[j])
                ;
            else
                break;
        }
    }
}

int mu(int n) {
    if(n==1)
        return 1;
    int res=-1;
    for(int i=1;i<=tot&&pri[i]<=n;i++){
        if(n%pri[i]==0){
            if(n%(pri[i]*pri[i])==0)
                return 0;
            else{
                n/=pri[i];
                res=-res;
            }
        }
    }
    if(n!=1)
        res=-res;
    return res;
}

ll n,m,k;

int fac[100];
int pfac[100];
int ftop=0;
void fj(int n) {
    ftop=0;
    for(int i=1; i<=tot; i++) {
        if(n%pri[i]==0) {
            fac[++ftop]=pri[i];
            pfac[ftop]=0;
            while(n%pri[i]==0) {
                n/=pri[i];
                pfac[ftop]++;
            }
        }
    }
    if(n!=1) {
        fac[++ftop]=n;
        pfac[ftop]=1;
    }
    return;
}

ll ans;

ll power(int p,int n) {
    if(n==0)
        return 1;
    ll res=1;
    while(n--)
        res*=p;
    return res;
}

ll LIMIT;

void dfs(int pos,ll cur) {
    if(cur>LIMIT)
        return;
    if(pos>ftop) {
        if(cur>=2&&cur<=LIMIT)
            ans+=1ll*mu(cur)*(LIMIT/cur);
        return;
    }
    for(int i=0; i<=pfac[pos]; i++) {
        dfs(pos+1,cur*power(fac[pos],i));
    }
}

ll G(ll n){
    LIMIT=n;
    ans=0;
    dfs(1,1);
    return ans;
}

ll F(ll n){
    return n-G(n);
}

ll solve(){
    ll L=1,R=1e18;
    while(1){
        ll MID=(L+R)>>1;
        //printf("MID=%lld\n",MID);
        if(MID==L){
            if(F(L)==k)
                return L;
            else
                return R;
        }
        ll FMID=F(MID);
        //printf("f(n)=%lld\n",FMID);
        if(FMID==k){
            R=MID;
        }
        else if(FMID<k){
            L=MID+1;
        }
        else{
            R=MID-1;
        }
    }
    return -1;
}

int main() {
#ifdef Yinku
    freopen("Yinku.in","r",stdin);
#endif // Yinku
    sieve(N);
    while(~scanf("%lld%lld",&m,&k)){
        fj(m);
        /*for(int i=1;i<=ftop;i++){
            printf("%d:%d\n",fac[i],pfac[i]);
        }*/
        printf("%lld\n",solve());
    }
}
posted @ 2019-05-16 20:45  韵意  阅读(193)  评论(0编辑  收藏  举报