Live2d Test Env

从HDU2588:GCD 到 HDU5514:Frogs (欧拉公式)

The greatest common divisor GCD(a,b) of two positive integers a and b,sometimes written (a,b),is the largest divisor common to a and b,For example,(1,2)=1,(12,18)=6. 
 (a,b) can be easily found by the Euclidean algorithm. Now Carp is considering a little more difficult problem: 
 Given integers N and M, how many integer X satisfies 1<=X<=N and (X,N)>=M.

InputThe first line of input is an integer T(T<=100) representing the number of test cases. The following T lines each contains two numbers N and M (2<=N<=1000000000, 1<=M<=N), representing a test case.OutputFor each test case,output the answer on a single line.Sample Input

3
1 1
10 2
10000 72

Sample Output

1
6
260

题意:求有多少个1<=X<=N,满足gcd(X,N)>=M。

思路:即求Σd=gcd(X,N)>=M;枚举d,而d是M的因子,不超过根号N个;对枚举的d,用欧拉公式求得有多少个X满足gcd(X,N)=d;

#include<bits/stdc++.h> 
using namespace std;
const int maxn=1000000;
int p[maxn+10],vis[maxn+10],phi[maxn],cnt;
void getprime()
{
    phi[1]=1;
    for(int i=2;i<=maxn;i++){
        if(!vis[i]) p[++cnt]=i,phi[i]=i-1;
        for(int j=1;j<=cnt&&i*p[j]<=maxn;j++){
            vis[i*p[j]]=1; phi[i*p[j]]=phi[i]*(p[j]-1);
            if(i%p[j]==0){
                phi[i*p[j]]=phi[i]*p[j];
                break;
            }
        }
    }
}
int tot,ans,fac[maxn];
void divide(int x)
{
    for(int i=1;i*i<=x;i++){
        if(x%i==0){
            fac[++tot]=i;
            if(i*i!=x) fac[++tot]=x/i;
        }
    }
}
map<int,int>PHI;
int getphi(int x)
{
    if(x<=maxn) return phi[x];
    if(PHI[x]) return PHI[x];
    int res=x;
    for(int i=2;i*i<=x;i++)
      if(x%i==0) {
         res=res/i*(i-1);
         while(x%i==0) x/=i;
      }
    if(x>1) res=res/x*(x-1);
    PHI[x]=res;
    return res;
}
int main()
{
    getprime();
    int T,N,M,i,j;
    scanf("%d",&T);
    while(T--){
        tot=ans=0;
        scanf("%d%d",&N,&M);
        divide(N);
        for(i=1;i<=tot;i++){
            if(N/fac[i]>=M) ans+=getphi(fac[i]);
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

---------------------------------分界线--------------------------------

再来看HDU5514。。。(虽然复杂度看似有些巧合)。

只要枚举M的因子,然后验证如果是属于某个gcd(a,M)的倍数,就可以累加其所到位子,求和的时候利用对称性,有公式Σ=φ(x)*m/2;。

 (容斥定理也可以做,但是我想不出来)。。。

#include<bits/stdc++.h> 
using namespace std;
#define ll long long
const int maxn=100000;
int p[maxn+10],vis[maxn+10],phi[maxn],cnt;
void getprime()
{
    phi[0]=1; phi[1]=1;
    for(int i=2;i<=maxn;i++){
        if(!vis[i]) p[++cnt]=i,phi[i]=i-1;
        for(int j=1;j<=cnt&&i*p[j]<=maxn;j++){
            vis[i*p[j]]=1; phi[i*p[j]]=phi[i]*(p[j]-1);
            if(i%p[j]==0){
                phi[i*p[j]]=phi[i]*p[j];
                break;
            }
        }
    }
}
int tot,fac[maxn];
void divide(int x)
{
    for(int i=1;i*i<=x;i++){
        if(x%i==0){
            fac[++tot]=i;
            if(i*i!=x) fac[++tot]=x/i;
        }
    }
}
int getphi(int x)
{
    if(x<=maxn) return phi[x];
    int res=x;
    for(int i=2;i*i<=x;i++)
      if(x%i==0) {
         res=res/i*(i-1);
         while(x%i==0) x/=i;
    }
    if(x>1) res=res/x*(x-1);
    return res;
}
int a[maxn],N,M;
bool check(int x)
{
    for(int i=1;i<=N;i++)
        if(x%a[i]==0) return true;
    return false;
}
int main()
{
    getprime();
    int T,Case=0,i; ll ans;
    scanf("%d",&T);
    while(T--){
        tot=ans=0;
        scanf("%d%d",&N,&M);
        for(i=1;i<=N;i++){
            scanf("%d",&a[i]);
            a[i]=__gcd(a[i],M);
        }
        divide(M);
        for(i=1;i<=tot;i++){
            if(fac[i]!=M&&check(fac[i])) ans+=(ll)getphi(M/fac[i])*M/2;
        }
          printf("Case #%d: %lld\n",++Case, ans);
    }
    return 0;
}

 

posted @ 2018-05-09 15:48  nimphy  阅读(245)  评论(0编辑  收藏  举报