莫比乌斯反演

数论的东西总是好难QAQ,像我这样的蒟蒻心态崩溃


一个好的讲解:莫比乌斯反演


做了点题,莫比乌斯反演解决的就是快速计算函数的问题。

你有一个函数F(n)要算,但是特别难算,但是你有另一个函数f(n),F(n)能由f(n)相加求得,而且是倍数关系

这个时候就可以利用莫比乌斯反演函数简化运算

还需要强大的数学运算水平QAQ


上题:

2301: [HAOI2011]Problem b

Time Limit: 50 Sec  Memory Limit: 256 MB
Submit: 6139  Solved: 2803
[Submit][Status][Discuss]

Description

对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数。



Input

第一行一个整数n,接下来n行每行五个整数,分别表示a、b、c、d、k

Output

共n行,每行一个整数表示满足要求的数对(x,y)的个数

Sample Input

2

2 5 1 5 1

1 5 1 5 2



Sample Output


14

3



HINT



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



了解莫比乌斯反演函数后很快就能看出,一道莫比乌斯反演的入手题

但是需要简化运算【还不会用编辑器时间紧就不写式子了,上面的链接讲的很清楚】


要注意的是通常遇到n / d这样的整除运算都是可以分块计算的

这题中用到的是满足(n / d) = (n / i)的最大的d = n / (n / i)

还用到了容斥原理


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<bitset>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define fo(i,x,y) for (int i = (x); i <= (y); i++)
#define Redge(u) for (int k = head[u]; k != -1; k = edge[k].next)
using namespace std;
const int maxn = 50005,maxm = 100005,INF = 1000000000;
int miu[maxn],prime[maxn],primei = 0,sum[maxn];
bitset<maxn> isn;
inline int read(){
	int out = 0,flag = 1;char c = getchar();
	while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
	while (c >= 48 && c <= 57) {out = out * 10 + c - 48; c = getchar();}
	return out * flag;
}
void init(){
	isn.set();
	miu[1] = 1;
	for (int i = 2; i < maxn; i++){
		if (isn[i]) prime[++primei] = i,miu[i] = -1;
		for (int j = 1; j <= primei && i * prime[j] < maxn; j++){
			isn[i * prime[j]] = false;
			if (i % prime[j] == 0){ miu[i * prime[j]] = 0; break; }
			miu[i * prime[j]] = -miu[i];
		}
	}
	for (int i = 1; i < maxn; i++) sum[i] = sum[i - 1] + miu[i];
}
int cal(int n,int m){
	if (n > m) swap(n,m);
	int ans = 0,nxt;
	for (int i = 1; i <= n; i = nxt + 1){
		nxt = min(n / (n / i),m / (m / i));
		ans += (sum[nxt] - sum[i - 1]) * (n / i) * (m / i);
	}
	return ans;
}
int main()
{
	init();
	int N,a,b,c,d,k;
	N = read();
	while (N--){
		a = read(); b = read(); c = read(); d = read(); k = read();
		a--; c--;
		a/=k;b/=k;c/=k;d/=k;
		printf("%d
",cal(b,d) - cal(b,c) - cal(a,d) + cal(a,c));
	}
	return 0;
}




原文地址:https://www.cnblogs.com/Mychael/p/8282824.html