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