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

来源:互联网 发布:淘宝申请退款流程 编辑:程序博客网 时间:2024/06/03 00:23

传送门

GCDTime Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 8784    Accepted Submission(s): 3260Problem DescriptionGiven 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.InputThe 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.OutputFor each test case, print the number of choices. Use the format in the example.Sample Input21 3 1 5 11 11014 1 14409 9Sample OutputCase 1: 9Case 2: 736427HintFor 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).

题目大意:
输入5个数,a, b, c, d, k, 其中 a = c = 1,所以 这题就是求[1,b],[1,d]最大公约数GCD为 k 的对数。而且没有顺序。

解题思路:
假设 GCD(x, y) == k,那么,x/k 与 y/k是肯定互素的,所以我们要求的就是[1,b/k],[1,d/k]之间互素的数的个数,所以我们很容易就想到的是欧拉函数,可以把b设置为小的那个数, 那么以y>x来保持唯一性
接下来分两种情况:
1. y <= b , 那么互素对数就是 1~a的欧拉函数的累计和(容易想到)
2. y >= b , 考虑用容斥原理,
3. 然后就随便搞一搞就行了。

#include <iostream>#include <cstring>#include <algorithm>#include <cstdio>#include <vector>using namespace std;typedef long long LL;const int MAXN = 1e5+5;bool flag[MAXN];///标记数组LL phi[MAXN];///欧拉函数值,i的欧拉函数值=phi[i]LL p[MAXN];///素因子的值LL cnt = 0;void Get_phi()///筛法求欧拉函数{    cnt = 0;    memset(flag, true, sizeof(flag));    phi[1] = 1;    for(int i=2; i<MAXN; i++)///线性筛法    {        if(flag[i])///素数        {            p[cnt++] = i;            phi[i] = i-1;///素数的欧拉函数值是素数 - 1        }        for(int j=0; j<cnt; j++)        {            if(i*p[j] > MAXN)                break;            flag[i*p[j]] = false;///素数的倍数,所以i*p[j]不是素数            if(i%p[j] == 0)///性质:i mod p == 0, 那么 phi(i * p) == p * phi(i)            {                phi[i*p[j]] = p[j] * phi[i];                break;            }            else                phi[i*p[j]] = (p[j]-1) * phi[i];///i mod p != 0, 那么 phi(i * p) == phi(i) * (p-1)        }    }}vector <LL> link[MAXN];void Init(){    for(LL i=1; i<MAXN; i++)    {        LL k = i;        for(LL j=0; p[j]*p[j]<=k; j++)        {            if(k%p[j] == 0)            {                link[i].push_back(p[j]);                while(k%p[j]==0)                    k /= p[j];            }            if(k == 1)                break;        }        if(k > 1)            link[i].push_back(k);    }}void init()     //求每一个数的质因数,vector储存{    LL i, j, k;    for(i = 1; i < MAXN; i++)    {        k = i;        for(j = 0; p[j]*p[j] <= k; j++)        {            if(k%p[j] == 0)            {                link[i].push_back(p[j]);                while(k%p[j] == 0)                    k /= p[j];            }            if(k == 1) break;        }        if(k > 1) link[i].push_back(k);    }}LL RongChi(LL a, LL b, LL num){    LL ret = 0;    for(LL i=a; i<link[num].size(); i++)    {        LL k = b/link[num][i];        ret += k - RongChi(i+1, k, num);    }    return ret;}int main(){    Get_phi();    Init();    int T;    LL a, b, c, d, k;    cin>>T;    for(int cas=1; cas<=T; cas++)    {        cin>>a>>b>>c>>d>>k;        if(k == 0)        {            printf("Case %d: 0\n", cas);            continue;        }        b/=k, d/=k;        if(b > d)            swap(b, d);        LL ret = 0;        for(int i=1; i<=b; i++)            ret += phi[i];        for(int i=b+1; i<=d; i++)            ret += b - RongChi(0, b, i);        printf("Case %d: %lld\n", cas,ret);    }    return 0;}
0 0
原创粉丝点击