zoukankan      html  css  js  c++  java
  • 从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
    ",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
    ",++Case, ans);
        }
        return 0;
    }
  • 相关阅读:
    Web前端学习第三天·fighting_常用的一些标签(一)
    Web前端学习第七天·fighting_CSS样式的编写和使用(二)
    Web前端学习第八天·fighting_使用CSS美化文字(一)
    WPF 自定义RadioButton样式
    WPF自定义控件与样式自定义按钮(Button)
    WPF 自定义Calendar样式(日历样式,周六周日红色显示)
    WPF 自定义TextBox带水印控件,可设置圆角
    WPF 自定义CheckBox样式
    常见web UI 元素操作 及API使用
    selenium定位下拉框
  • 原文地址:https://www.cnblogs.com/hua-dong/p/9014720.html
Copyright © 2011-2022 走看看