HDU1695-GCD(数论-欧拉函数-容斥)

GCD

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 5454    Accepted Submission(s): 1957

Problem Description

Given 5 integers: a, b, c, d, k, you‘re to find x in a...b, y in c...d that GCD(x, y) = k. GCD(x, y) means the greatest common divisor of x and y. Since the number of choices may be very large, you‘re only required to output the total number of different number
pairs.

Please notice that, (x=5, y=7) and (x=7, y=5) are considered to be the same.

Yoiu can assume that a = c = 1 in all test cases.

Input

The input consists of several test cases. The first line of the input is the number of the cases. There are no more than 3,000 cases.

Each case contains five integers: a, b, c, d, k, 0 < a <= b <= 100,000, 0 < c <= d <= 100,000, 0 <= k <= 100,000, as described above.

Output

For each test case, print the number of choices. Use the format in the example.

Sample Input

2
1 3 1 5 1
1 11014 1 14409 9

Sample Output

Case 1: 9
Case 2: 736427

Hint

For the first sample input, all the 9 pairs of numbers are (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 5), (3, 4), (3, 5).

题意: 求(1,a) 和(1,b) 两个区间 公约数为k的对数的个数

思路:将a,b分别处以k,就能够转化为(1,a/k)和(1,b/k)两个区间两两互质的个数,能够先用欧拉函数求出(1,a)两两互质的个数,(a+1。b) 能够分解质因数。由于质因数的个数最多为7能够用容斥原理计算。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <string>
#include <algorithm>
#include <queue>
using namespace std;

const int maxn = 10000+10;
const int maxxn = 100000+10;
typedef long long ll;
int a,b,gcd;
ll ans;
bool isPrime[maxn];
ll minDiv[maxxn],phi[maxxn],sum[maxxn];
vector<int> prime,cnt[maxxn],digit[maxxn];

void getPrime(){
    prime.clear();
    memset(isPrime,1,sizeof isPrime);
    for(int i = 2;i < maxn; i++){
        if(isPrime[i]){
            prime.push_back(i);
            for(int j = i*i; j < maxn; j+=i){
                isPrime[j] = 0;
            }
        }
    }
}

void getPhi(){
    for(ll i = 1; i < maxxn; i++){
        minDiv[i] = i;
    }
    for(ll i = 2; i*i < maxxn; i++){
        if(minDiv[i]==i){
            for(int j = i*i; j < maxxn; j += i){
                minDiv[j] = i;
            }
        }
    }
    phi[1] = 1;
    sum[1] = 1;
    for(ll i = 2; i < maxxn; i++){
        phi[i] = phi[i/minDiv[i]];
        if((i/minDiv[i])%minDiv[i]==0){
            phi[i] *= minDiv[i];
        }else{
            phi[i] *= minDiv[i]-1;
        }
        sum[i] = phi[i]+sum[i-1];
    }
}

void getDigit(){
    for(ll i = 1; i < maxxn; i++){
        int x = i;
        for(int j = 0; j < prime.size()&&x >= prime[j]; j++){
            if(x%prime[j]==0){
                digit[i].push_back(prime[j]);
                int t = 0;
                while(x%prime[j]==0){
                    t++;
                    x /= prime[j];
                }
                cnt[i].push_back(t);
            }
        }
        if(x!=1){
            digit[i].push_back(x);
            cnt[i].push_back(1);
        }
    }
}

int main(){
    getPrime();
    getPhi();
    getDigit();
    int ncase,T=1;
    cin >> ncase;
    while(ncase--){
        int t1,t2;
        scanf("%d%d%d%d%d",&t1,&a,&t2,&b,&gcd);
        if(gcd==0){
            printf("Case %d: 0\n",T++,ans);
            continue;
        }else{
            if(a > b) swap(a,b);
            a /= gcd,b /= gcd;
            ans = sum[a];
            for(ll i = a+1; i <= b; i++){
                int d = digit[i].size();
                int t = 0;
                vector<int> di;
                for(int k = 1; k < (1<<d); k++){
                    di.clear();
                    for(int f = 0; f < d; f++){
                        if(k&(1<<f)){
                            di.push_back(digit[i][f]);
                        }
                    }
                    int ji = 1;
                    for(int f = 0; f < di.size(); f++){
                        ji *= di[f];
                    }
                    if(di.size()%2==0){
                        t -= a/ji;
                    }else{
                        t += a/ji;
                    }
                }
                ans += a-t;
            }
            printf("Case %d: ",T++);
            cout<<ans<<endl;
        }

    }
    return 0;
}
时间: 2024-07-31 14:32:19

HDU1695-GCD(数论-欧拉函数-容斥)的相关文章

hdu1695(莫比乌斯)或欧拉函数+容斥

题意:求1-b和1-d之内各选一个数组成数对,问最大公约数为k的数对有多少个,数对是有序的.(b,d,k<=100000) 解法1: 这个可以简化成1-b/k 和1-d/k 的互质有序数对的个数.假设b=b/k,d=d/k,b<=d.欧拉函数可以算出1-b与1-b之内的互质对数,然后在b+1到d的数i,求每个i在1-b之间有多少互质的数.解法是容斥,getans函数参数的意义:1-tool中含有rem位置之后的i的质因子的数的个数. 在 for(int j=rem;j<=factor[i

hdu 1695 GCD 欧拉函数+容斥

题意:给定a,b,c,d,k x属于[1 , c],y属于[1 , d],求满足gcd(x,y)=k的对数.其中<x,y>和<y,x>算相同. 思路:不妨设c<d,x<=y.问题可以转化为x属于[1,c / k ],y属于[1,d/k ],x和y互质的对数. 那么假如y<=c/k,那么对数就是y从1到c/k欧拉函数的和.如果y>c/k,就只能从[ c/k+1 , d ]枚举,然后利用容斥.详见代码: /****************************

HDU 1695 GCD 欧拉函数+容斥定理

输入a b c d k求有多少对x y 使得x在a-b区间 y在c-d区间 gcd(x, y) = k 此外a和c一定是1 由于gcd(x, y) == k 将b和d都除以k 题目转化为1到b/k 和1到d/k 2个区间 如果第一个区间小于第二个区间 讲第二个区间分成2部分来做1-b/k 和 b/k+1-d/k 第一部分对于每一个数i 和他互质的数就是这个数的欧拉函数值 全部数的欧拉函数的和就是答案 第二部分能够用全部数减去不互质的数 对于一个数i 分解因子和他不互质的数包括他的若干个因子 这个

hdu 6390 欧拉函数+容斥(莫比乌斯函数) GuGuFishtion

http://acm.hdu.edu.cn/showproblem.php?pid=6390 题意:求一个式子 题解:看题解,写代码 第一行就看不出来,后面的sigma公式也不会化简.mobius也不会 就自己写了个容斥搞一下(才能维持现在的生活) //别人的题解https://blog.csdn.net/luyehao1/article/details/81672837 #include <iostream> #include <cstdio> #include <cstr

bzoj 2818 GCD 数论 欧拉函数

bzoj[2818]Gcd Description 给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的数对(x,y)有多少对. Input 一个整数N Output 如题 Sample Input 4 Sample Output 4 HINT hint对于样例(2,2),(2,4),(3,3),(4,2) 1<=N<=10^7 题解一(自己yy) phi[i]表示与x互质的数的个数 即gcd(x,y)=1 1<=y<x ∴对于x,y 若a为素数 则gcd(xa,

HDU1695 GCD (欧拉函数+容斥原理)

求(1,b)区间和(1,d)区间里面gcd(x, y) = k的数的对数(1<=x<=b , 1<= y <= d). b和d分别除以k之后的区间里面,只需要求gcd(x, y) = 1就可以了,这样子求出的数的对数不变. 这道题目还要求1-3 和 3-1 这种情况算成一种,因此只需要限制x<y就可以了 只需要枚举x,然后确定另一个区间里面有多少个y就可以了.因此问题转化成为区间(1, d)里面与x互素的数的个数 先求出x的所有质因数,因此(1,d)区间里面是x的质因数倍数的

POJ 2154 Color(组合数学-波利亚计数,数论-欧拉函数,数论-整数快速幂)

Color Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 7693   Accepted: 2522 Description Beads of N colors are connected together into a circular necklace of N beads (N<=1000000000). Your job is to calculate how many different kinds of th

HDU 4002 Find the maximum(数论-欧拉函数)

Find the maximum Problem Description Euler's Totient function, φ (n) [sometimes called the phi function], is used to determine the number of numbers less than n which are relatively prime to n . For example, as 1, 2, 4, 5, 7, and 8, are all less than

uva 11317 - GCD+LCM(欧拉函数+log)

题目链接:uva 11317 - GCD+LCM 题目大意:给定n,求出1~n里面两两的最大公约的积GCD和最小公倍数的积LCM,在10100进制下的位数. 解题思路:在n的情况下,对于最大公约数为i的情况又phi[n/i]次.求LCM就用两两乘积除以GCD即可. #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; ty