T^TOJ - 1251 - 。◕‿◕。TMD - 欧拉函数 - 质因数分解

http://www.fjutacm.com/Problem.jsp?pid=1251
想了很久,一开始居然还直接枚举因子d,计算重复了。

首先你要找与n的最大公因子大于m的x的个数。

\[\sum\limits_{x=1}^n [gcd(x,n)>=m]\]

不能直接枚举d,d必须是n的因子,否则与n的gcd都不可能是d。

\[\sum\limits_{d=m \& d|n}^n \sum\limits_{x=1}^n [gcd(x,n)==d]\]

后面那个有点眼熟?

\[\sum\limits_{d=m \& d|n}^n \sum\limits_{x=1}^{n/d} [gcd(x,n/d)==1]\]

果然是欧拉函数:

\[\sum\limits_{d=m \& d|n}^n \varphi(n/d)\]

然后,查了一下,因子的个数实在不会太多1e8不到1000个,1e17不到100000个。

那就直接质因数分解然后搜索。

一发AC。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=100000;

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;
        }
    }
}

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

int t,n,m;

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;

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

void dfs(int pos,int cur) {
    if(pos>ftop) {
        if(cur>=m)
            ans+=phi(n/cur);
        return;
    }
    for(int i=0; i<=pfac[pos]; i++) {
        dfs(pos+1,cur*power(fac[pos],i));
    }
}

int main() {
#ifdef Yinku
    freopen("Yinku.in","r",stdin);
#endif // Yinku
    sieve(N);
    scanf("%d",&t);
    while(t--) {
        scanf("%d%d",&n,&m);
        ans=0;
        fj(n);
        dfs(1,1);
        printf("%I64d\n",ans);
    }
}

猜你喜欢

转载自www.cnblogs.com/Yinku/p/10877188.html
今日推荐