BZOJ2301(75/600)

对于给出的 n 个询问,每次求有多少个数对 (x,y) ,满足 a ≤ x ≤ b , c ≤ y ≤ d ,且 gcd(x,y) = k , gcd(x,y) 函数为 x 和 y 的最大公约数。

Input
第一行一个整数n,接下来n行每行五个整数,分别表示a、b、c、d、k

Output
共n行,每行一个整数表示满足要求的数对(x,y)的个数

Sample Input
2

2 5 1 5 1

1 5 1 5 2

Sample Output
14

3

Hint

100%的数据满足:1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000

莫比乌斯还是那个莫比乌斯
但是学会了换元来实现分块fn=求和 u(i)*f(i*n)这个玩意可以通过换元把n替换成n/k
然后莫比乌斯函数就可以前缀和了
然后再通过去除重复的数可以分块了
比如你从5里面找gcd为4和3的数量一样….

#include<bits/stdc++.h>
using namespace std;
long long q, w, e, r, t;
#define int long long 
template <class T> inline void in(T &x) {
    T f = 1; char c; while ((c = getchar()) < '0' || c > '9') if (c == '-') f = -1;
    x = c - '0';
    while ((c = getchar()) >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0'; x *= f;
}
typedef long long ll;
const int  maxn = 50105;
int  normal[maxn];
int  mu[maxn];
int  prime[maxn],sum[maxn];
int  pcnt, u = 0;
void Init()
{
    memset(normal, 0, sizeof(normal));
    mu[1] = 1;
    pcnt = 0;
    for (int  i = 2; i<maxn; i++)
    {
        if (!normal[i])
        {
            prime[pcnt++] = i;
            mu[i] = -1;
        }
        for (int  j = 0; j<pcnt&&i*prime[j]<maxn; j++)
        {
            normal[i*prime[j]] = 1;
            if (i%prime[j]) mu[i*prime[j]] = -mu[i];
            else
            {
                mu[i*prime[j]] = 0;
                break;
            }
        }
    }
    for(int a=1;a<=maxn;a++)sum[a]=sum[a-1]+mu[a];
}
//long long  f[maxn], F[maxn];
int jiejue(int z,int y)
{
    if(z>y)swap(z,y);
    int fs=0;
    if(!z)return 0;
    for(int a=1,b;a<=z;a=b+1)
    {
        b=min(z/(z/a),y/(y/a));
        fs+=(z/a)*(y/a)*(sum[b]-sum[a-1]);
    }
    return fs;
}
main()
{
    Init();
    int T;
    cin >> T;
    while (T--)
    {
        in(q), in(w), in(e), in(r), in(t);
        long long tt = 0;
        tt+=jiejue(w/t,r/t)+jiejue((q-1)/t,(e-1)/t)-jiejue((q-1)/t,r/t)-jiejue((e-1)/t,w/t);
        printf("%lld\n", tt);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值