洛谷 P2257 YY的GCD(莫比乌斯反演)

Description:

神犇YY虐完数论后给傻×kAc出了一题

给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对

kAc这种傻×必然不会了,于是向你来请教……

多组输入

Input:

第一行一个整数T 表述数据组数

接下来T行,每行两个正整数,表示N, M

T = 10000

N, M <= 10000000

Output

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

Sample Input:

2
10 10
100 100

Sample Output:

30
2791

题目链接

题意为求出 T T T ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) ∈ p r i m e ] \sum\limits_{i=1}^{n} \sum\limits_{j=1}^{m}[gcd(i, j) \in prime] i=1nj=1m[gcd(i,j)prime]

首先我们令 n < m n < m n<m ,之后对此式进行化简,将 g c d ( i , j ) gcd(i,j) gcd(i,j) 设为变量 p p p

∑ p = 1 n ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = p ] ( p ∈ p r i m e ) \sum\limits_{p=1}^{n}\sum\limits_{i=1}^{n} \sum\limits_{j=1}^{m} [gcd(i, j)=p] (p\in prime) p=1ni=1nj=1m[gcd(i,j)=p](pprime)

化简得

∑ p = 1 n ∑ i = 1 ⌊ n p ⌋ ∑ j = 1 ⌊ m p ⌋ [ g c d ( i , j ) = 1 ] \sum\limits_{p=1}^{n}\sum\limits_{i=1}^{\lfloor \frac{n}{p} \rfloor} \sum\limits_{j=1}^{\lfloor \frac{m}{p} \rfloor}[gcd(i, j)=1] p=1ni=1pnj=1pm[gcd(i,j)=1]

利用莫比乌斯函数性质可得

∑ p = 1 n ∑ i = 1 ⌊ n p ⌋ ∑ j = 1 ⌊ m p ⌋ ∑ d ∣ g c d ( i , j ) μ ( d ) \sum\limits_{p=1}^{n}\sum\limits_{i=1}^{\lfloor \frac{n}{p} \rfloor} \sum\limits_{j=1}^{\lfloor \frac{m}{p} \rfloor} \sum\limits_{d|gcd(i, j)} \mu (d) p=1ni=1pnj=1pmdgcd(i,j)μ(d)

考虑枚举 d d d

∑ p = 1 n ∑ d = 1 ⌊ n p ⌋ μ ( d ) ∑ i = 1 ⌊ n p ⌋ [ d ∣ i ] ∑ j = 1 ⌊ m p ⌋ [ d ∣ j ] ​ \sum\limits_{p=1}^{n}\sum\limits_{d=1}^{\lfloor \frac{n}{p} \rfloor} \mu (d) \sum\limits_{i=1}^{\lfloor \frac{n}{p} \rfloor}[d|i] \sum\limits_{j=1}^{\lfloor \frac{m}{p} \rfloor}[d|j]​ p=1nd=1pnμ(d)i=1pn[di]j=1pm[dj]

其中 ∑ i = 1 ⌊ n p ⌋ [ d ∣ i ] \sum\limits_{i=1}^{\lfloor \frac{n}{p} \rfloor}[d|i] i=1pn[di] [ 1 , ⌊ n p ⌋ ] [1,\lfloor \frac{n}{p} \rfloor] [1,pn] d d d 的倍数, ∑ j = 1 ⌊ m p ⌋ [ d ∣ j ] \sum\limits_{j=1}^{\lfloor \frac{m}{p} \rfloor}[d|j] j=1pm[dj] [ 1 , ⌊ m p ⌋ ] [1,\lfloor \frac{m}{p} \rfloor] [1,pm] d d d 的倍数,两项可化简为 ⌊ n p d ⌋ \lfloor \frac{n}{pd} \rfloor pdn ⌊ m p d ⌋ \lfloor \frac{m}{pd} \rfloor pdm

这样可以推导出 ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) ∈ p r i m e ] = ∑ d = 1 ⌊ n p ⌋ μ ( d ) ⌊ n p d ⌋ ⌊ m p d ⌋ ( p ∈ p r i m e , n < m ) \sum\limits_{i=1}^{n} \sum\limits_{j=1}^{m}[gcd(i, j) \in prime]=\sum\limits_{d=1}^{\lfloor \frac{n}{p} \rfloor} \mu (d) \lfloor \frac{n}{pd} \rfloor \lfloor \frac{m}{pd} \rfloor(p \in prime,n<m) i=1nj=1m[gcd(i,j)prime]=d=1pnμ(d)pdnpdm(pprime,n<m)

其中莫比乌斯函数 μ \mu μ 可以用线性筛筛出,但是这样 O ( n ) O(n) O(n) 枚举 d d d 的计算复杂度在多组输入中还不是正确的复杂度

考虑继续化简该式,令 T = p d T=pd T=pd ,代入得

∑ T = 1 n ∑ p ∣ T μ ( T p ) ⌊ n T ⌋ ⌊ m T ⌋ \sum\limits_{T=1}^{n} \sum\limits_{p|T} \mu (\frac{T}{p}) \lfloor \frac{n}{T} \rfloor \lfloor \frac{m}{T} \rfloor T=1npTμ(pT)TnTm

整理得

∑ T = 1 n ⌊ n T ⌋ ⌊ m T ⌋ ∑ p ∣ T μ ( T p ) \sum\limits_{T=1}^{n} \lfloor \frac{n}{T} \rfloor \lfloor \frac{m}{T} \rfloor \sum\limits_{p|T} \mu (\frac{T}{p}) T=1nTnTmpTμ(pT)

发现其中 ∑ p ∣ T μ ( T p ) \sum\limits_{p|T} \mu (\frac{T}{p}) pTμ(pT) 部分可以做前缀和预处理,另外 ⌊ n T ⌋ ⌊ m T ⌋ \lfloor \frac{n}{T} \rfloor \lfloor \frac{m}{T} \rfloor TnTm 部分使用分块优化就可以愉(jian)快(nan)地 A C AC AC 掉这道题目啦

AC代码:

#include 
using namespace std;

const int maxn = (int)(1e7 + 5);

bool IsPrime[maxn];
int Tot;
int Prime[maxn];
int Mu[maxn];
long long F[maxn];
long long Prefix[maxn];

void Moblus() {
	for (int i = 0; i < maxn; ++i) IsPrime[i] = true;
	Mu[1] = 1;
	for (int i = 2; i < maxn; ++i) {
		if (IsPrime[i]) {
			Prime[Tot++] = i;
			Mu[i] = -1;
		}
		for (int j = 0; j < Tot && Prime[j] * i < maxn; ++j) {
			IsPrime[i * Prime[j]] = false;
			if (i % Prime[j] == 0) {
				Mu[i * Prime[j]] = 0;
				break;
			}
			Mu[i * Prime[j]] = -Mu[i];
		}
	}
	for (int i = 0; i < Tot; ++i) {
		for (int j = 1; Prime[i] * j < maxn; ++j) {
			F[j * Prime[i]] += Mu[j];
		}
	}
	for (int i = 1; i < maxn; ++i) Prefix[i] = Prefix[i - 1] + F[i];
}

long long Solve(int N, int M) {
	if (N > M) swap(N, M);
	long long Res = 0;
	for (int t = 1, tp; t <= N; t = tp + 1) {
		tp = min(N / (N / t), M / (M / t));
		Res += (Prefix[tp] - Prefix[t - 1]) * (N / t) * (M / t);
	}
	return Res;
}

int T;
int N, M;

int main(int argc, char *argv[]) {
	Moblus();
	scanf("%d", &T);
	for (int Case = 1; Case <= T; ++Case) {
		scanf("%d%d", &N, &M);
		printf("%lld\n", Solve(N, M));
	}
	return 0;
}

你可能感兴趣的:(洛谷 P2257 YY的GCD(莫比乌斯反演))