poj 2480 数学

题意:给定一个整数n (1<n<2^31),  求1~n的数与n的最大公约数之和,即 ∑gcd(i, n)     (1<=i <=n)   。

分析:枚举n的因数k,求有多少个 i ,使gcd(i,n)=k。

设gcd(i,n)=k, 其中 i=ak, n=bk, 则gcd(ak, bk)=k  =>  gcd(a,b)=1,  所以有φ(b)个 i ,使gcd(i,n)=k。

答案为:  ∑k*φ(n/k)     (k|n)

 

 

#define Max 46355
LL pri[Max], p, n;
LL ans;
bool vis[Max] ;
void getPrime(LL n){//大范围内素数的线性筛法
    for(LL i = 2; i <= n; i++){
        if( !vis[i]) pri[p++] = i;
        for(int j = 0;j < p && pri[j] * i <= n; j++){
                vis[pri[j] * i] = true;
                if(i % pri[j] == 0) break;
        }
    }
}

const int M = 20;
LL cnt[M], pr[M], q;
void init(LL n){

    memset(cnt, 0, sizeof cnt);//缺少这句,RE半天

    q=0; ans=0;
    for(LL i = 0; pri[i] * pri[i] <= n ; i++){
        if(n%pri[i]==0){
            pr[q] = pri[i];
            while(n % pri[i] == 0) {
                n /= pri[i];
                cnt[q]++;
            }
            q++;
        }
    }
    if(n > 1) {pr[q] = n; cnt[q]++; q++;}
}

LL euler1(LL n){//求φ(n)
    LL res = n;
    for(LL i = 0; pri[i] * pri[i] <= n ; i++)
        if(n % pri[i] == 0){
            res = res / pri[i] * ( pri[i] - 1 );
            while(n % pri[i] == 0) n /= pri[i];
        }
    if(n > 1) res = res / n * (n - 1);
    return res;
}

void d(LL s, int i, int f){
    if(s*s>n) return;
    if(f){
        ans += s*euler1(n/s);
        if(s*s!=n) ans += (n/s)*euler1(s);
    }       //cout<<s<<' '<<i<<' '<<pr[i]<<' '<<cnt[i]<<' '<<endl;
    if(i>=q) return;
    d(s, i+1, 0);
    FOR(j, 0, cnt[i]){
        s*=pr[i];
        d(s, i+1, 1);
    }
}
/*
void d(LL s, int i, int f){
    if(f){
        ans += s*euler1(n/s);
        //if(s*s!=n) ans += (n/s)*euler1(s);
    }       //cout<<s<<' '<<i<<' '<<pr[i]<<' '<<cnt[i]<<' '<<endl;
    if( i>=q ) return;
    d(s, i+1, 0);
    FOR(j, 0, cnt[i]){
        s*=pr[i];
        d(s, i+1, 1);
    }
}*/

int main(){
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    #endif

    getPrime(Max);
    while(cin>>n){
        init(n);
        d(1, 0, 1);
        /*ans = 0;
        int sq=sqrt(n*1.0);
        FOE(i,1,sq){
            if(n%i==0){
                ans+=i*euler1(n/i);
                if(i*i!=n) ans+=(n/i)*euler1(i);
            }
        }*/
        cout<<ans<<endl;
    }
    return 0;
}

 

posted @ 2013-05-21 16:56  心向往之  阅读(155)  评论(0编辑  收藏  举报