51nod - 1192 Gcd表中的质数 莫比乌斯反演 + 分块

有一个M * N的表格,行与列分别是1 - M和1 - N,格子中间写着行与列的最大公约数Gcd(i, j)(1 <= i <= M, 1 <= j <= N)。

例如:M = 5, n = 4。

 

  1 2 3 4 5

1 1 1 1 1 1

2 1 2 1 2 1

3 1 1 3 1 1

4 1 2 1 4 1

 

给出M和N,求这张表中有多少个质数。

 收起

输入

第1行:一个数T,表示后面用作输入测试的数的数量。(1 <= T <= 1000)
第2 - T + 1行:每行2个数M,N,中间用空格分隔,表示表格的宽和高。(1 <= M, N <= 5 * 10^6)

输出

共T行,每行1个数,表示表格中质数的数量。

输入样例

2
10 10
100 100

输出样例

30
2791

题解:反演的公式记住就行,主要是把F(x) 和 f(x) 找到

要先把莫比乌斯函数求出来,把结果后部分预处理出个前缀和,然后前面通过枚举d分块来求,直接枚举会超时

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 5e6 + 10;
int prime[N], len;
bool isp[N];
int mu[N];
int sum[N], a[N];
void init() {
	mu[1] = 1;
	for(int i = 2; i < 5000000; i++) {
		if(!isp[i]) {
			prime[len++] = i;
			mu[i] = -1;
		}
		for(int j = 0; j < len && (ll)i * prime[j] < 5000000; j++) {
			isp[i * prime[j]] = 1;
			if(i % prime[j] == 0) {
				mu[i * prime[j]] = 0;
				break;
			} else {
				mu[i * prime[j]] = -mu[i];
			}
		}
	}
	for(int i = 0; i < len; i++) 
		for(int j = prime[i]; j < 5000000; j += prime[i])
			a[j] += mu[j / prime[i]];
	for(int i = 1; i <= 5000000; i++)
		sum[i] = sum[i - 1] + a[i];
}
int main() {
	init();
	int T , CM, r;
	int n, m;
	ll ans;
	scanf("%d", &T);
	while(T--) {
		scanf("%d %d", &n, &m);
		ans = 0;
		CM = min(n, m);
		/*
		for(int i = 1; i <= CM; i++)
			ans += (ll)(n / i) * (m / i) * a[i];
		*/
		for(int i = 1; i <= CM; i = r + 1) {
			r = min(n / (n / i), m / (m / i));
			ans += (ll)(n / i) * (m / i) * (sum[r] - sum[i - 1]);
		}
		
		printf("%lld\n", ans);
	}
	return 0;	
} 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值