zoukankan      html  css  js  c++  java
  • T^TOJ

    求单个莫比乌斯函数忘记算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
    ",MID);
            if(MID==L){
                if(F(L)==k)
                    return L;
                else
                    return R;
            }
            ll FMID=F(MID);
            //printf("f(n)=%lld
    ",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
    ",fac[i],pfac[i]);
            }*/
            printf("%lld
    ",solve());
        }
    }
    
  • 相关阅读:
    学习MeteoInfo二次开发教程(十一)
    学习MeteoInfo二次开发教程(十)
    学习MeteoInfo二次开发教程(九)
    学习MeteoInfo二次开发教程(八)
    linux 03 命令 续
    linux 02 基础命令
    linux 01 基础命令
    第九节课 迭代器生成器、模块和包
    第八节课 文件、异常、文件的输入输出
    第七节课 内置函数、作用域、闭包、递归
  • 原文地址:https://www.cnblogs.com/Yinku/p/10877880.html
Copyright © 2011-2022 走看看