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

题目链接http://acm.hdu.edu.cn/showproblem.php?pid=1695 题目大意:求[1..b]中的x和[1..d]中的y有多少gcd(x,y) = k. 思路: 预备知识: 容斥原理求数区间[1..r]中与n互质的数的个数.   Here 要求gcd(x,y) = k,则等价于求 gcd(x/k,y/k) = 1.所以问题转化成求[1..b/k]和[1..d/k]中有多少对gcd(x,y) = 1. 又因为此题要求gcd(1,3)和gcd(3,1)算一个,所以我们不妨按x < y来求. 接下来,我们枚举x的值,然后便转化为求[x..d/k]区间中与x互质的数的个数,用容斥原理解决. [x..d/k] = [1..d/k] - [1..x-1],[1..d/k]我们用上面的容斥原理方法就可以解决,[1..x-1]虽然也可以用容斥,但速度较慢,明显可以用更快的欧拉函数做。  

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define MID(x,y) ((x+y)>>1)

using namespace std;

typedef long long LL;    //max long long == 9223372036854775807LL

LL phi(LL n)
{
    if (n == 1) return 0;
    LL i,sum=n;
    for(i=2; i*i<=n; i++)
    {
        if(n%i==0)
        {
            sum = sum / i * (i-1);
            do
            {
                n/=i;
            }
            while(n%i==0);
        }
    }
    if(n>1) sum = sum / n * (n - 1);
    return sum;
}

int solve(int r, int n){
    if (r == 0) return 0;
    int res = 0;
    vector  p;
    for (int i = 2; i * i <= n; i ++){
        if (n % i == 0){
            p.push_back(i);
            while(n % i == 0){
                n /= i;
            }
        }
        if (n == 1) break;
    }
    if (n > 1)  p.push_back(n);
    for (int msk = 1; msk < (1 << p.size()); msk ++){
        int mult = 1, bit = 0;
        for (int i = 0; i < p.size(); i ++){
            if (msk & (1 << i)){
                bit ++;
                mult *= p[i];
            }
        }
        int cur = r / mult;
        if (bit % 2 == 1){
            res += cur;
        }
        else{
            res -= cur;
        }
    }
    return r - res;
}

int main(){
    int t, caseo = 1;
    cin>>t;
    while(t --){
        int a,b,c,d,k;
        cin>>a>>b>>c>>d>>k;
        if (k == 0){
            cout< d){
            int tmp = d;
            d = b;
            b = tmp;
        }
        LL ans = 0;
        for (int i = 1; i <= b; i ++){
            ans += (LL)solve(d, i) - phi(i);
        }
        cout<

转载于:https://www.cnblogs.com/AbandonZHANG/archive/2012/12/02/4114183.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值