【BZOJ 2301】【HAOI 2011】Problem b

今天才知道莫比乌斯反演还可以这样:$$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} \right \rfloor\left \lfloor \frac{m}{i} \right \rfloor$$反演后$$f(i)=\sum_{i|d}\mu(\frac{d}{i})F(d)=\sum_{i|d}\mu(\frac{d}{i})\left \lfloor \frac{n}{i} \right \rfloor\left \lfloor \frac{m}{i} \right \rfloor$$因为$\left \lfloor \frac{n}{i} \right \rfloor\left \lfloor \frac{m}{i} \right \rfloor$的取值是$O(2(\sqrt{n}+\sqrt{m})$的,所以除法枚举这些取值再乘上区间内的$\mu$值就可以做到$O(n\sqrt{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\n", QQ);
	}
	return 0;
}

233

posted @ 2016-04-23 15:44  abclzr  阅读(...)  评论(...编辑  收藏