今天才知道莫比乌斯反演还可以这样:$$F(n)=sum_{n|d}f(d) Rightarrow f(n)=sum_{n|d}mu(frac{d}{n})F(d)$$我好弱,,,对于$$F(i)=left lfloor frac{n}{i} ight floorleft lfloor frac{m}{i} ight floor$$反演后$$f(i)=sum_{i|d}mu(frac{d}{i})F(d)=sum_{i|d}mu(frac{d}{i})left lfloor frac{n}{i} ight floorleft lfloor frac{m}{i} ight floor$$因为$left lfloor frac{n}{i} ight floorleft lfloor frac{m}{i} ight floor$的取值是$O(2(sqrt{n}+sqrt{m})$的,所以除法枚举这些取值再乘上区间内的$mu$值就可以做到$O(nsqrt{n})$时间内解决所有询问,区间内的$mu$值用前缀和相减就可以了
#include<cstdio>
#include<cstring>
#include<algorithm>
#define read(x) x=getint()
using namespace std;
const int N = 50000;
int getint() {
int k = 0, fh = 1; char c = getchar();
for(; c < '0' || c > '9'; c = getchar())
if (c == '-') fh = -1;
for(; c >= '0' && c <= '9'; c = getchar())
k = k * 10 + c - '0';
return k * fh;
}
bool check[N + 3];
int prime[N + 3], mu[N + 3], sum[N + 3];
void shai() {
memset(check, 0, sizeof(check));
sum[1] = 1; mu[1] = 1; int num = 0;
for(int i = 2; i <= N; ++i) {
if (!check[i]) {
prime[++num] = i;
mu[i] = -1;
}
for(int j = 1; j <= num; ++j) {
if (i * prime[j] > N) break;
check[i * prime[j]] = 1;
if (i % prime[j] == 0) {mu[i * prime[j]] = 0; break;}
else mu[i * prime[j]] = - mu[i];
}
sum[i] = sum[i - 1] + mu[i];
}
}
long long Q(int n, int m) {
if (n > m) swap(n, m);
long long ret = 0;
for(int i = 1, la = 0; i <= n; i = la + 1) {
la = min(n / (n / i), m / (m / i));
ret += (long long) (sum[la] - sum[i - 1]) * (n / i) * (m / i);
}
return ret;
}
int main() {
shai();
int a, b, c, d, k, T;
long long QQ;
read(T);
while (T--) {
read(a); read(b); read(c); read(d); read(k);
QQ = Q(b / k, d / k) - Q((a - 1) / k, d / k) - Q(b / k, (c - 1) / k) + Q((a - 1) / k, (c - 1) / k);
printf("%lld
", QQ);
}
return 0;
}
233