hdu1695 GCD(反演)

Problem Description
Given 5 integers: a, b, c, d, k, you’re to find x in a…b, y in c…d that GCD(x, y) = k. GCD(x, y) means the greatest common divisor of x and y. Since the number of choices may be very large, you’re only required to output the total number of different number pairs.
Please notice that, (x=5, y=7) and (x=7, y=5) are considered to be the same.

Yoiu can assume that a = c = 1 in all test cases.

Input
The input consists of several test cases. The first line of the input is the number of the cases. There are no more than 3,000 cases.
Each case contains five integers: a, b, c, d, k, 0 < a <= b <= 100,000, 0 < c <= d <= 100,000, 0 <= k <= 100,000, as described above.

Output
For each test case, print the number of choices. Use the format in the example.

Sample Input

2
1 3 1 5 1
1 11014 1 14409 9

Sample Output

Case 1: 9
Case 2: 736427

Hint
For the first sample input, all the 9 pairs of numbers are (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 5), (3, 4), (3, 5).



分析:

题目有一个重要的条件:Yoiu can assume that a = c = 1 in all test cases.

因此题目要求的就是:这里写图片描述
我们现在的问题就是,如何求解:这里写图片描述

这里写图片描述

这样我们就可以解决这个问题了

写完了之后,跑出来的答案比Simple Output要大
注意到题面说:(a,b)视为一个无序数对

说白了就是规定:a<=b

这就引出了一个新的问题:去重

手玩了小数据之后,

发现重复只会出现在:两个元素的定义域重叠的这一部分

也就是说,如果我们计算的是:这里写图片描述
那么答案中会包括:(x1,y1),(y1,x1)(其中gcd(x1,y1)=z 且x1!=y1)以及(z,z)

其中重复的元素有:ans/2

所以我们把答案更改一下:
这里写图片描述

tip

当d=0的时候,直接返回0

在计算这里写图片描述的时候,我们有玄学的分块法

注意:

如果没有a=c=1的条件

那么答案的计算就相当于一个利用二维前缀和求矩阵答案

//这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
#define ll long long

using namespace std;

const int N=100005;
int sshu[N],tot=0,a,b,c,d,k;
ll mu[N];
bool no[N];

void make()
{
    mu[1]=1;
    memset(no,0,sizeof(no));
    for (int i=2;i<N;i++)
    {
        if (!no[i])
        {
            sshu[++tot]=i;
            mu[i]=-1;
        }
        for (int j=1;j<=tot&&i*sshu[j]<N;j++)
        {
            no[i*sshu[j]]=1;
            if (i%sshu[j]==0)
            {
                mu[i*sshu[j]]=0;
                break;
            }
            mu[i*sshu[j]]=-mu[i];
        }
    }

    for (int i=2;i<N;i++) mu[i]+=mu[i-1];
}

ll solve(int n,int m,int d)    //玄学的分块 
{
    int i,j;
    if (!n||!m||!d) return 0;
    n/=d; m/=d; 
    int last;
    ll ans=0;
    for (int i=1;i<=min(n,m);i=last+1)
    {
        last=min(n/(n/i),m/(m/i));
        ans+=(mu[last]-mu[i-1])*(n/i)*(m/i);
    }
    return ans;
}

int main()
{
    int T;
    scanf("%d",&T);
    make();
    for (int cas=1;cas<=T;cas++)
    {
        scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
        a--; c--;
        printf("Case %d: ",cas);
        ll ans=solve(b,d,k)-solve(min(b,d),min(b,d),k)/2;
        printf("%lld\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值