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);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章