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

来源:互联网 发布:南方大数据100指数 编辑:程序博客网 时间:2024/05/17 08:04

http://acm.hdu.edu.cn/showproblem.php?pid=1695


[1,b]中选择一个x,[1,d]中选择一个y,使得gcd(x,y) = k问题等价于在[1,b/k],[1,d/k]中选择x,y使得gcd(x,y) = 1

我们保证b小于d,那么就可以遍历[1,d/k]这个区间得到所有满足条件的素数对.

分为两种情况:

1.[1,b]时直接使用欧拉定理计算

2.[b,d]时利用容斥原理来间接计算:b - (有一个共同质因数的总和) + (有两个共同质因数的总和) - (有三个共同质因数的总和)……

那么问题来了:

欧拉函数(积性函数)

对正整数n,欧拉函数是少于或等于n的数中与n互质的数的数目。若n是质数p的k次幂,φ(n)=p^k - p^(k-1)=(p-1)p^(k-1),因为除了p的倍数外,其他数都跟n互质.

通式:φ(x)=x*(1-1/p1)*(1-1/p2)*(1-1/p3)*(1-1/p4)*…..*(1-1/pn), 其中p1, p2……pn为x的所有质因数,x是不为0的整数.

            φ(x)=φ(m)*φ(n)(m*n = x && gcd(m,n) = 1)

代码实现

void init(){    euler[1] = 1;    for(int i=2; i<MAX; i++){        if(!euler[i]){///没有计算过的是素数            for(int j=i; j<MAX; j+=i){                if(!euler[j])   euler[j] = j;                euler[j] -= euler[j]/i;                prime[j][num[j]++] = i;///记录每一个合数分解的素数序列            }        }        ///euler[i] += euler[i-1];    }}
容斥原理

在计数时,必须注意无一重复,无一遗漏。为了使重叠部分不被重复计算,人们研究出一种新的计数方法,这种方法的基本思想是:先不考虑重叠的情况,把包含于某内容中的所有对象的数目先计算出来,然后再把计数时重复计算的数目排斥出去,使得计算的结果既无遗漏又无重复,这种计数的方法称为容斥原理.


AC代码:

#include <stdio.h>#include <string.h>#include <iostream>#include <algorithm>using namespace std;typedef long long LL;const int MAX = 100010;LL euler[MAX];int prime[MAX][10],num[MAX];void init(){    euler[1] = 1;    for(int i=2; i<MAX; i++){        if(!euler[i]){            for(int j=i; j<MAX; j+=i){                if(!euler[j])   euler[j] = j;                euler[j] -= euler[j]/i;                prime[j][num[j]++] = i;            }        }        euler[i] += euler[i-1];    }}int main(){    init();    int cas,t=0;    scanf("%d",&cas);    while(cas--){        LL a, b, c, d, k, ans;        cin >> a >> b >> c >> d >> k;        if(k == 0)  ans = 0;        else{            if(b > d)   swap(b, d);            b /= k, d /= k;            ans = euler[b];            for(int i=b+1; i<=d; i++){///容斥原理                int t = num[i], tmp = b;                for(int j=1; j<(1 << t); j++){                    int x = 1, y = 1;                    for(int k=0; k<t; k++)                        if(j & (1 << k))                            x *= prime[i][k], y *= -1;                    tmp += y*b/x;                }                ans += tmp;            }                    }        printf("Case %d: ",++t);        cout << ans << endl;    }    //system("pause");    return 0;}



0 0
原创粉丝点击