hdu 1695 莫比乌斯反演

本文介绍了一种利用莫比乌斯函数求解在指定区间内满足最大公约数等于给定值的数对数量的方法。通过数学推导与算法实现,解决了在1到b与1到d范围内寻找gcd(x,y)=k的所有数对(x,y)的数量问题。

传送门

题意:给你5个数a,b,c,d,k

在a~b中选一个x, c~d中选一个y,满足gcd(x,y) = k , 求(x,y) 的对数 

a, b, c, d, k, 0 < a <= b <= 100,000, 0 < c <= d <= 100,000, 0 <= k <= 100,000

在题目描述的最后一行有一句话,多组里面所有的a和c都是1

然后题目变成

在1~b中选一个x, 1~d中选一个y,满足gcd(x,y) = k , 求(x,y) 的对数 

 

先把问题就转化为求1~a区间 和 1~b区间,gcd(x,y) = 1对数的问题

设f(d)为满足gcd(x,y)=d的x,y的对数

我们根据莫比乌斯第二公式来做

那F(1) = f(1) + f(2) + f(3) + ....

F(2) = f(2) + f(4) + f(6) +.....

我们可以看出F(d)就是满足gcd(x,y)为d的倍数的x,y的对数

那F(d)的公式就容易求了

F(d) = (a/d) * (b/d)

(在1~a中,有a/d个数是d的倍数,在1~b中,有b/d个数是d的倍数,这些数不管怎么选择,构成的gcd(x,y)都是d的倍数)

 

#include<cstring>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=1e6+5;
int tot;
int mu[N],vis[N],prime[N];
void init()
{
    mu[1]=1;
    for(int i=2;i<N;i++)
    {
        if(!vis[i])
        {
            prime[tot++]=i;
            mu[i]=-1;
        }
        for(int j=0;j<tot&&i*prime[j]<N;j++)
        {
            vis[i*prime[j]]=1;
            if(i%prime[j]) mu[i*prime[j]]=-mu[i];
            else
            {
                mu[i*prime[j]]=0;
                break;
            }
        }
    }
}
int main()
{
    int t;
    int a,b,c,d,k;
    cin>>t;
    init();
    int cas=1;
    while(t--)
    {
        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 ans=0;
        for(int i=1;i<=b;i++)
        {
            ans+=1ll*mu[i]*(d/i)*(b/i);
        }
        //我们现在求完了总对数,但是题目要求的类似(5,7)和(7,5)算一种
        //所以接下来我们开始去重
        ll temp=0;
        for(int i=1;i<=b;i++)
        {
            temp+=1ll*mu[i]*(b/i)*(b/i);
        }
        //比如a=5,b=7那么(4,6)这样子的区间不可能有重复的(6,4)
        //所以重复的部分只在1~a中,所以最后减去一半的重复区间就好了 
        printf("Case %d: %lld\n",cas++,ans-temp/2);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值