2820: YY的GCD

2820: YY的GCD

Time Limit: 10 Sec   Memory Limit: 512 MB
Submit: 1461   Solved: 762
[ Submit][ Status][ Discuss]

Description

神犇YY虐完数论后给傻×kAc出了一题给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对kAc这种
傻×必然不会了,于是向你来请教……多组输入

Input

第一行一个整数T 表述数据组数接下来T行,每行两个正整数,表示N, M

Output

T行,每行一个整数表示第i组数据的结果

Sample Input

2
10 10
100 100

Sample Output

30
2791

HINT

T = 10000

N, M <= 10000000

Source

[ Submit][ Status][ Discuss]



莫比乌斯反演

还是一样,,(每组询问默认n<=m)

f[i]:最大公约数为i的个数

F[i]:以i为约数的个数

F[i] = [n/i]*[m/i]

f[i] = ∑u(d/i)*F[i]  (d是i的倍数)

不过本题,,需要求gcd(i,j)为质数的个数,,

上述只能在根号n的时间内求出单个f[i]

列出一般解法的式子

ans = ∑u(d/p)[n/d]*[m/d]  (p是质数,d是p的倍数)

换种思路,不直接枚举d,而是枚举一个i,使得

ans = ∑u(i)*[n/(pi)]*[m/(pi)]

令T = pi,换元

ans = ∑u(T/p)*[n/T]*[m/T]

调一下∑的顺序

ans = ∑[n/T]*[m/T]*∑u[T/p]

根据原始的式子,T必须是p的倍数,且p是个素数

[n/T]*[m/T]  这玩意的取值显然是只有2(根号n+根号m)

枚举之

如果我们能O(1)得出∑u[T/p]

那么算法的复杂度就是O(Q根号n)  (Q为询问个数)

按照之前的前缀和思路

对于∑u[T/p],只有T%p == 0的情况莫比乌斯函数对于T才有效

筛法后处理下就好O(nlogn)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
using namespace std;

const int maxn = 1E7 + 10;
typedef long long LL;

LL mu[maxn],sum[maxn];
int n,m,T;
bool not_prime[maxn];

LL Mu(LL n,LL m)
{
	LL ret = 0;
	int last,tail = min(n,m);
	for (LL i = 1; i <= tail; i = last + 1) {
		last = min(n/(n/i),m/(m/i));
		ret += (n/i)*(m/i)*(sum[last] - sum[i-1]);
	}
	return ret;
}

int main()
{
	#ifdef DMC
		   freopen("DMC.txt","r",stdin);
	#endif
	
	for (int i = 1; i < maxn; i++) mu[i] = 1;
	for (int i = 2; i < maxn; i++)
		if (!not_prime[i]) {
			mu[i] = -1;
			for (int j = 2; ; j++) {
				int x = i*j;
				if (x >= maxn) break;
				not_prime[x] = 1;
				mu[x] *= mu[i];
				if (j % i == 0) mu[x] = 0;
			}
		}
	for (int i = 2; i < maxn; i++)
		if (!not_prime[i]) 
			for (int j = 1; ; j++) {
				int x = i*j;
				if (x >= maxn) break;
				sum[x] += mu[j];
			}
	for (int i = 1; i < maxn; i++) sum[i] += sum[i-1];
	cin >> T;
	while (T--) {
		scanf("%d%d\n",&n,&m);
		printf("%lld\n",Mu(n,m));
	}
	
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值