Counting Rhyme

题目信息

题目链接

Luogu CF1884DCodeforces 1884D

题面翻译

给定长度为 n 的序列 a。对于 1i<jn,若不存在 k[1,n] 使得 akaiakaj 那么 (i,j) 是好的。

求出好的数对数量。1ain106

题目描述

You are given an array of integers a1,a2,,an .

A pair of integers (i,j) , such that 1i<jn , is called good, if there does not exist an integer k ( 1kn ) such that ai is divisible by ak and aj is divisible by ak 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 ( 1t2104 ). The description of the test cases follows.

The first line of each test case contains a single integer n ( 1n106 ).

The second line of each test case contains n integers a1,a2,,an ( 1ain ).

It is guaranteed that the sum of n over all test cases does not exceed 106 .

输出格式

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) .

题目思路

因为 akaiakaj,所以 akgcd(ai,aj)

假设 f(x) 表示 gcd(ai,aj)=x 的对数。

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

g(x) 表示 gcd(ai,aj)y 的个数,这个可以直接暴力 O(nlnn) 求。

于是 f(x)=iμ(i)gix 就行。

只需要再看 x 是否合法。同样可以把不合法的筛掉,即 gcd(ai,aj) 不能是 ak 的倍数。O(nlnn)

结束。

代码

#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
数学容斥原理

本文作者:gutongxing

本文链接:https://www.cnblogs.com/gutongxing/p/18233143

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   辜铜星  阅读(9)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起