zoukankan      html  css  js  c++  java
  • hdu2588 GCD 给定n,m。求x属于[1,n]。有多少个x满足gcd(x,n)>=m; 容斥或者欧拉函数

    GCD
    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 2155    Accepted Submission(s): 1093
    
    
    Problem Description
    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.
     
    
    Input
    The 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.
     
    
    Output
    For each test case,output the answer on a single line.
     
    
    Sample Input
    
    3
    1 1
    10 2
    10000 72
    
     
    
    Sample Output
    
    1
    6
    260
    
    
    
    欧拉函数做法:
    /**
    题目:GCD
    链接:http://acm.hdu.edu.cn/showproblem.php?pid=2588
    题意:给定n,m。求x属于[1,n]。有多少个x满足gcd(x,n)>=m;
    思路:
    x -> [1,n]
    
    d = gcd(x,n) >= m
    
    d肯定为n的约数。
    
    对一个确定的d = gcd(x,n);
    
    那么:gcd(x/d,n/d) = 1;
    
    满足上面式子的x为:f(n/d); f(y)表示y的欧拉函数。
    
    sigma(f(n/d)) (d为n的约数且d>=m);
    
    f(y) = y*(p1-1)/p1*(p2-1)/p2...*(pe-1)/pe;
    
    */
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cstdio>
    #include<vector>
    #include<map>
    #include<set>
    #include<cmath>
    #include<queue>
    #define LL long long
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    ll Euler(ll x)
    {
        ll n = x;
        for(int i = 2; i*i<=x; i++){
            if(x%i==0){
                n = n/i*(i-1);
                while(x%i==0)x/=i;
            }
        }
        if(x>1){
           n = n/x*(x-1);
        }
        return n;
    }
    vector<int> v;
    int main()
    {
        int T;
        int n, m;
        cin>>T;
        while(T--)
        {
            scanf("%d%d",&n,&m);
            v.clear();
            for(int i = 1; i*i<=n; i++){
                if(n%i==0){
                    if(i*i==n){
                        if(i>=m) v.push_back(i);
                    }
                    else{
                        if(i>=m) v.push_back(i);
                        if(n/i>=m) v.push_back(n/i);
                    }
                }
            }
            int len = v.size();
            int cnt = 0;
            for(int i = 0; i < len; i++){
                cnt += Euler(n/v[i]);
            }
            printf("%d
    ",cnt);
        }
        return 0;
    }
    
    容斥做法:
    /**
    题目:GCD
    链接:http://acm.hdu.edu.cn/showproblem.php?pid=2588
    题意:给定n,m。求x属于[1,n]。有多少个x满足gcd(x,n)>=m;
    思路:
    
    显然d = gcd(x,n)中的d一定是n的约数。
    
    显然d = gcd(d,n); 先获得所有>=m的d;
    
    那么d的倍数为x=k*d,如果小于等于n,则一定也满足gcd(x,n)>=m;
    
    k = n/d; 如果对每个d这样计算,会有重复的计算。
    
    当d = 2, 3时候,x=6会多计算一次。
    
    所以要对所有的d进行容斥处理。
    
    问题转化为:n的约数为d,求解d>=m的所有的d在n范围内至少有一个是d的倍数的数有多少个。
    
    
    
    */
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cstdio>
    #include<vector>
    #include<map>
    #include<set>
    #include<cmath>
    #include<queue>
    #define LL long long
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    vector<int> v;
    int a[10004], z;  ///注意a数组要开大些,约数个数还是不是100就够的。
    ll gcd(ll a,ll b)
    {
        return b==0?a:gcd(b,a%b);
    }
    ll rc(ll n)
    {
        ll sum = 0;
        ll mult;
        int ones;
        int len = v.size();
        int m = (1<<len);
        //奇加偶减
        for(int i = 1; i < m; i++){
            ones = 0;
            mult = 1;
            for(int j = 0; j<len; j++){
                if(i&(1<<j)){
                    ones++;
                    mult = mult/gcd(mult,v[j])*v[j];
                    if(mult>n) break;
                }
            }
            if(ones%2==0){
                sum -= n/mult;
            }else
            {
                sum += n/mult;
            }
        }
        return sum;
    }
    int main()
    {
        int T;
        int n, m;
        cin>>T;
        while(T--)
        {
            scanf("%d%d",&n,&m);
            v.clear();
            z = 0;
            for(int i = 1; i*i<=n; i++){
                if(n%i==0){
                    if(i*i==n){
                        if(i>=m) a[z++] = i;
                    }
                    else{
                        if(i>=m) a[z++] = i;
                        if(n/i>=m) a[z++] = n/i;
                    }
                }
            }
            ///出去包含的,比如2,4那么4要去掉。以为4的倍数一定是2的倍数。
            sort(a,a+z);
            for(int i = 0; i < z; i++){
                int sign = 0;
                for(int j = 0; j < i; j++){
                    if(a[i]%a[j]==0){
                        sign = 1; break;
                    }
                }
                if(sign==0){
                    v.push_back(a[i]);
                }
            }
            printf("%lld
    ",rc(n));
        }
        return 0;
    }
    
    
     
  • 相关阅读:
    ruby 正则表达式 匹配中文
    ruby 正则表达式 匹配所有符合规则的信息
    MobileNetV2: Inverted Residuals and Linear Bottlenecks
    MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications
    SqueezeNet: AlexNet-level accuracy with 50x fewer parameters and <0.5MB model size
    LeetCode 409——最长回文串
    LeetCode 516——最长回文子序列
    LeetCode 5——最长回文子串
    LeetCode 300——最长上升子序列
    动态规划之——最长公共子串和矩阵链乘法
  • 原文地址:https://www.cnblogs.com/xiaochaoqun/p/6844226.html
Copyright © 2011-2022 走看看