[HAOI2011]Problem b

题意

组询问,给定 , 求 并且 = 的数对数量。

()

解题思路

  • 定义 表示 并且 满足 的数对数量。

容斥易得,本题的答案即是:

那么现在我们的目标是在 的时间内快速求出

考虑对于原式进行化简,原式即:

首先是把原式里面的 提出来:

下一步则是 转化为 :

又因为 : 等价于 &&

然后我们可以知道, 内的所有数中 的倍数一共有 个。所以式子进一步化简:

现在就可以整一个整除分块乱搞哩!1

#include <bits/stdc++.h>
using namespace std;
#define int long long
inline int read() {
    int x = 0, flag = 1;
    char ch = getchar();
    for( ; ch > '9' || ch < '0' ; ch = getchar()) if(ch == '-') flag = -1;
    for( ; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 3) + (x << 1) + ch - '0';
    return x * flag;
}

const int MAXN = 1e5 + 500;
int Prime[MAXN], mu[MAXN],tot = 0;
bool book[MAXN];
int T,a,b,c,d,k;

void GetPrime() {
    mu[1] = 1;
    for(int i = 2 ; i <= 6e4 ; i ++) {
        if(!book[i]) Prime[++ tot] = i, mu[i] = -1;
        for(int j = 1 ; j <= tot ; j ++) {
            if(Prime[j] * i > 6e4) break;
            book[Prime[j] * i] = 1;
            if(i % Prime[j] == 0) break;
            mu[i * Prime[j]] = -mu[i];
        }
    }
    for(int i = 1 ; i <= 6e4 ; i ++) mu[i] = mu[i - 1] + mu[i];
    return ;
}

int calc(int a, int b) {
    int Ans = 0;
    int mx=a / k, my = b / k;
    for(int l = 1 ,r ;l <= min (mx, my) ; l = r + 1) {
        r = min(mx / (mx / l), my / (my / l));
        Ans += (mx / l) * (my / l) * (mu[r] - mu[l - 1]);
    }
    return Ans;
}

signed main() {
    GetPrime();
    T = read();
    while(T --) {
        a = read(), b = read(), c = read(), d = read(); k = read();
        printf("%lld\n", calc(b, d) - calc(b, c - 1) - calc(a - 1, d) + calc(a - 1, c - 1));
    }
    return  0;
}