HDU 5514 欧拉函数应用

前置技能:

<=i且与i互质的数的和是phi(i)*i/2

思路:

显然每个人的步数是gcd(a[i],m)

把m的所有因数预处理出来

1~m-1中的每个数 只会被gcd(m,i)筛掉一遍

//By SiriusRen
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=100050;
typedef long long ll;
int cases,n,m,a[N],s[N],tp,I=1;
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int get_phi(int x){
    int t=x;
    for(int i=2;i*i<=x;i++)if(x%i==0){
        t-=t/i;
        while(x%i==0)x/=i;
    }if(x>1)t-=t/x;
    return t;
}
int main(){
    for(scanf("%d",&cases);I<=cases;I++){
        long long ans=0;tp=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]),a[i]=gcd(a[i],m);
        sort(a+1,a+1+n);
        n=unique(a+1,a+1+n)-a-1;
        for(int i=1;i*i<=m;i++)if(m%i==0){
            if(i*i==m)s[++tp]=i;
            else{
                s[++tp]=i;
                if(i!=1)s[++tp]=m/i;
            }
        }
        for(int i=1;i<=tp;i++)
            for(int j=1;j<=n;j++)if(s[i]%a[j]==0){
                ans+=get_phi(m/s[i]);break;
            }
        printf("Case #%d: %lld\n",I,1ll*ans*m/2);
    }
}

 

posted @ 2018-08-01 15:38  SiriusRen  阅读(145)  评论(0编辑  收藏  举报