Counting Rhyme

题目信息

题目链接

Luogu CF1884DCodeforces 1884D

题面翻译

给定长度为 \(n\) 的序列 \(a\)。对于 \(1\leq i<j\leq n\),若不存在 \(k\in[1,n]\) 使得 \(a_k\mid a_i\)\(a_k\mid a_j\) 那么 \((i,j)\) 是好的。

求出好的数对数量。\(1\le a_i\le n\leq 10^6\)

题目描述

You are given an array of integers $ a_1, a_2, \ldots, a_n $ .

A pair of integers $ (i, j) $ , such that $ 1 \le i < j \le n $ , is called good, if there does not exist an integer $ k $ ( $ 1 \le k \le n $ ) such that $ a_i $ is divisible by $ a_k $ and $ a_j $ is divisible by $ a_k $ at the same time.

Please, find the number of good pairs.

输入格式

Each test contains multiple test cases. The first line contains the number of test cases $ t $ ( $ 1 \le t \le 2 \cdot 10^4 $ ). The description of the test cases follows.

The first line of each test case contains a single integer $ n $ ( $ 1 \le n \le 10^6 $ ).

The second line of each test case contains $ n $ integers $ a_1, a_2, \ldots, a_n $ ( $ 1 \le a_i \le n $ ).

It is guaranteed that the sum of $ n $ over all test cases does not exceed $ 10^6 $ .

输出格式

For each test case, output the number of good pairs.

样例 #1

样例输入 #1

6
4
2 4 4 4
4
2 3 4 4
9
6 8 9 4 6 8 9 4 9
9
7 7 4 4 9 9 6 2 9
18
10 18 18 15 14 4 5 6 8 9 10 12 15 16 18 17 13 11
21
12 19 19 18 18 12 2 18 19 12 12 3 12 12 12 18 19 16 18 19 12

样例输出 #1

0
3
26
26
124
82

提示

In the first test case, there are no good pairs.

In the second test case, here are all the good pairs: $ (1, 2) $ , $ (2, 3) $ , and $ (2, 4) $ .

题目思路

因为 \(a_k\mid a_i\)\(a_k\mid a_j\),所以 \(a_k\mid \gcd(a_i,a_j)\)

假设 \(f(x)\) 表示 \(\gcd(a_i,a_j)=x\) 的对数。

我们发现这个很难求,于是我们在定义一个状态:

\(g(x)\) 表示 \(\gcd(a_i,a_j)\mid y\) 的个数,这个可以直接暴力 \(O(n\ln n)\) 求。

于是 \(f(x)=\displaystyle \sum_{i}\mu(i)g_{ix}\) 就行。

只需要再看 \(x\) 是否合法。同样可以把不合法的筛掉,即 \(gcd(a_i,a_j)\) 不能是 \(a_k\) 的倍数。\(O(n\ln n)\)

结束。

代码

#include<bits/stdc++.h>
#pragma G++ optimize(2)
#define int long long
using namespace std;
const int MAXN = 1e6+10;
int mu[MAXN+10],prime[MAXN+10];
bitset<MAXN+10> is_prime;
void Euler_sieve(){
	mu[1] = 1;
	for(int i = 2;i<MAXN;i++){
		if(!is_prime[i]){
			prime[++prime[0]] = i;
			mu[i] = -1;
		}
		for(int j = 1;j<=prime[0]&&i*prime[j]<MAXN;j++){
			is_prime[i*prime[j]] = 1;
			if(i%prime[j]==0){
				mu[i*prime[j]] = 0;
				break;
			}else{
				mu[i*prime[j]] = -mu[i];
			}
		}
	}
}
int T,n,a[MAXN+10],g[MAXN+10];
int sum[MAXN+10] = {0};bitset<MAXN+10> vis,be;
signed main(){
	Euler_sieve();
	scanf("%lld",&T);
	while(T--){
		scanf("%lld",&n);
		vis.reset();be.set();
		for(int i = 1;i<=n;i++) sum[i] = 0;
		for(int i = 1;i<=n;i++){
			scanf("%lld",&a[i]);
			vis[a[i]] = 1;
			sum[a[i]]++;
		}
		int _ = vis._Find_first();
		while(_<=n){
			for(int i = _;i<=n;i+=_){
				be[i] = 0;
			}
			_ = vis._Find_next(_);
		}
		for(int i = 1;i<=n;i++){
			g[i] = 0;
			for(int j = i;j<=n;j+=i){
				g[i] += sum[j];
			}
			g[i] = g[i]*(g[i]-1)/2;
		}
		int ans = 0;
		for(int i = 1;i<=n;i++){
			for(int j = 1;j*i<=n;j++){
				ans += g[i*j]*mu[j]*be[i];
			}
		}
		printf("%lld\n",ans);
	}
	return 0;
}

tag

Codeforces
数学容斥原理

posted @ 2024-06-05 15:31  GuTongXing  阅读(18)  评论(0)    收藏  举报