# [bzoj2301] [HAOI2011]Problem b(莫比乌斯反演)

2
2 5 1 5 1
1 5 1 5 2

14
3

### Hint

100%的数据满足：1≤n≤50000，1≤a≤b≤50000，1≤c≤d≤50000，1≤k≤50000

### Solution

$f(d) = \sum^n_{i=1}\sum^m_{j=1}gcd(i,j) == d$
$F(d) = \sum^n_{i=1}\sum^m_{j=1} d | gcd(i,j) = \lfloor{m/d}\rfloor * \lfloor{n/d}\rfloor$
$F(d) = \sum_{d|k}f(k)$

### Code

#include <cstdio>
#include <iostream>
using namespace std;

const int maxn = 1e5 + 10;
int n;
int v[maxn], mu[maxn];

void pre() {
for(int i = 2; i < maxn; i++) {
if(v[i] <= 0)
for(int j = i; j < maxn; j += i) v[j] = i;
}

mu[1] = 1;
for(int i = 2; i < maxn; i++) {
if(v[i] == v[ i / v[i]]) mu[i] = 0;
else mu[i] = -mu[i / v[i]];
}
for(int i = 2; i < maxn; i++) mu[i] += mu[i-1];
}

inline long long cal(int n, int m) {
if(n > m) swap(n, m);
long long res = 0;
for(int i = 1, j; i <= n; i = j + 1) {
j = min(m / (m / i), n / (n / i));
res += (long long)(mu[j] - mu[i - 1]) * (m / i) * (n / i);
}
return res;
}

int main() {
pre();
int t, a , b, c, d, k;
scanf("%d", &t);
for(int tt = 1; tt <= t; tt++) {
scanf("%d%d%d%d%d", &a, &b, &c, &d, &k);
if(k == 0) {
printf("0\n"); continue;
}
a--, c--;
a /= k, b /= k, c /= k, d /= k;
long long ans = 0;
ans += cal(a, c) + cal(b, d);
ans -= cal(a, d) + cal(b, c);
printf("%lld\n", ans);
}
return 0;
}
posted @ 2017-01-09 23:58  ZegWe  阅读(...)  评论(...编辑  收藏