Hdu 1695 GCD - 欧拉函数 + 容斥

题目大意:

给定两个区间[1,b]和[1,d],x∈[1,b],y∈[1,d],问有多少种组合,使得gcd(x,y) = k。

题目分析:

将gcd(x,y) = k 化简得 gcd(x/k,y/k) = 1,既表示在两个区间中求多少对数字互质。

最简单的做法就是在区间中枚举,但是有一个条件 gcd(x,y) 和gcd(y,x)属于同一种情况,所以要避免枚举重复的。

如果不想枚举重复的,那么就要保证x<y。

这样,不妨将区间分为两部分:[1,min(b/k,d/k)][min(b/k,d/k)+1,max(b/k,d/k)]

就是在[1,min(b/k,d/k)]中找x,在[min(b/k,d/k)+1,max(b/k,d/k)]找y。

这里就可以用欧拉函数了。

欧拉函数\varphi(n)是小于或等于n的正整数中与n互质的数的数目。

所以在区间[1,min(b/k,d/k)]中,令n = min(b/k,d/k),那么满足条件的数目为\varphi(n)

对于j∈[min(b/k,d/k)+1,max(b/k,d/k)],只需要找出在[1,min(b/k,d/k)] 中有多少数字和j互质。

所以这道题目就转变为求欧拉函数和运用容斥原理计数的问题了。

[1,min(b/k,d/k)]中:

与i互质的数的个数 = 每个i的质因数倍数的个数 - 每两个i的质因数乘积的倍数个数 + 每三个i的质因数乘积的倍数个数······

下面是代码:

#include <stdio.h>
#define maxn 101000

long long eule[maxn];
int prime[maxn][10];
int num[maxn];

//筛选法求欧拉函数和质因数
void init()
{
    for(int i = 1; i < maxn; i++) eule[i] = 0;
    eule[1] = 1;
    for(int i = 2; i < maxn; i++)
    {
        if(!eule[i])
        {
            for(int j = i; j < maxn; j += i)
            {
                if(!eule[j]) eule[j] = j;//代码很巧妙,nice
                eule[j] = eule[j] / i * (i-1);
                prime[j][num[j]++] = i;
            }
        }
        eule[i] += eule[i-1];
    }
}

//容斥原理计数
long long dfs(int x,int A,int j)
{
    long long res = 0;
    for(int i = x; i < num[j]; i++)
    {
        res += A/prime[j][i] - dfs(i+1,A/prime[j][i],j);
    }
    return res;
}
int main()
{
    int t;
    int flag = 0;
    int a,b,c,d,k;
    init();
    scanf("%d",&t);
    while(t--)
    {
        flag++;
        scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
        if(k == 0)
        {
            printf("Case %d: 0\n",flag);
            continue;
        }
        a = b < d ? b : d;
        c = b > d ? b : d;
        a /= k;
        c /= k;
        long long ans = eule[a];
        for(int i = a+1; i <= c; i++) ans += a - dfs(0,a,i);
        printf("Case %d: %I64d\n",flag,ans);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值