[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;
} 
京公网安备 11010502036488号