HDU - 1695 GCD(莫比乌斯反演)

题目地址
题意:令x为1到b中的一个数,y为1到d中的一个数,求gcd(x,y)=k的无序对个数,即(x=3,y=5)和(x=5,y=3)这种算同一个。
思路:莫比乌斯经典套路。首先列式子
  a n s = ∑ i = 1 b ∑ j = i d [ g c d ( i , j ) = = k ] \ ans=\sum_{i=1}^b\sum_{j=i}^d [gcd(i,j)==k]  ans=i=1bj=id[gcd(i,j)==k](因为是无序对,所以j必须从i开始)
  a n s = ∑ i = 1 ⌊ b k ⌋ ∑ j = i ⌊ d k ⌋ [ g c d ( i , j ) = = 1 ] \ ans=\sum_{i=1}^{\lfloor \frac{b}{k} \rfloor}\sum_{j=i}^{\lfloor \frac{d}{k} \rfloor} [gcd(i,j)==1]  ans=i=1kbj=ikd[gcd(i,j)==1]
然后后面利用莫比乌斯函数性质
在这里插入图片描述
  a n s = ∑ i = 1 ⌊ b k d ′ ⌋ ∑ j = i ⌊ d k d ′ ⌋ ∑ d ′ ∣ g c d ( i , j ) m u ( d ′ ) \ ans=\sum_{i=1}^{\lfloor \frac{b}{kd'} \rfloor}\sum_{j=i}^{\lfloor \frac{d}{kd'} \rfloor} \sum_{d'|gcd(i,j)}{mu(d')}  ans=i=1kdbj=ikdddgcd(i,j)mu(d)
把d’提到前面
  a n s = ∑ d ′ = 1 ⌊ b k ⌋ m u ( d ′ ) ∑ i = 1 ⌊ b k d ′ ⌋ ∑ j = i ⌊ d k d ′ ⌋ 1 \ ans=\sum_{d'=1}^{\lfloor \frac{b}{k} \rfloor}{mu(d')}\sum_{i=1}^{\lfloor \frac{b}{kd'} \rfloor}\sum_{j=i}^{\lfloor \frac{d}{kd'} \rfloor}1  ans=d=1kbmu(d)i=1kdbj=ikdd1
然后就完了,d’是可以直接枚举的,后面显然可以o(1)算出,大概是
x = ⌊ b k d ′ ⌋ x=\lfloor \frac{b}{kd'} \rfloor x=kdb y = ⌊ d k d ′ ⌋ y=\lfloor \frac{d}{kd'} \rfloor y=kdd
那么就是   ∑ y − x + 1 y \ \sum_{y-x+1}^y  yx+1y 求和公式就ok了。
因为hdoj在维修,就过了下样例,输出也没按格式,样例是大样例应该没什么问题。
还真有问题,这题k居然可以等于0,记得特判

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <set>
#include <stack>
#include <map>
#include <algorithm>
#include <fstream>
using namespace std;
typedef long long ll;
typedef unsigned int uint32;
const int maxn = 3e6 + 100;
const int INF = 0x7fffffff;
const int mod = 1e9+7;
const ll mod1 = 998244353;
const ll base = 137;
const double Pi = acos(-1.0);
const int G = 3;
bool vis1[maxn];
int mu[maxn];
int cnt;
int prime[maxn];
void Init()
{
    mu[1] = 1;
    cnt = 0;
    for(int i=2; i<maxn; i++)
    {
        if(!vis1[i])
        {
            prime[cnt++] = i;
            mu[i] = -1;
        }
        for(int j=0; j<cnt&&i*prime[j]<maxn; j++)
        {
            vis1[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;
	cin>>t;
    int T=1;
	Init();
	while(t--)
	{
		int a,b,c,d,k;
		scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
        if(k==0)
        {
            printf("Case %d: ",T++);
            puts("0");
            continue;
        }
		if(b>d) swap(b,d);
		ll ans=0;
		for(int i=1;i<=b/k;i++)
		{
			int x=b/k/i;
			int y=d/k/i;
		
        	ans=1ll*ans+1ll*mu[i]*(y-x+1+y)*x/2;
		}
        printf("Case %d: ",T++);
		cout<<ans<<endl;
	}
	system("pause");
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值