题目链接 https://vjudge.net/problem/HDU-5072
题目大意
给定数组
a
i
a_i
ai求满足以下两个条件其中一个的三元组
(
a
,
b
,
c
)
(a,b,c)
(a,b,c)的数量
p
s
:
(
a
,
b
,
c
)
=
(
b
,
c
,
a
)
ps:(a,b,c)=(b,c,a)
ps:(a,b,c)=(b,c,a)
1.
(
a
,
b
)
=
1
,
(
a
,
c
)
=
1
,
(
b
,
c
)
=
1
(a,b)=1,(a,c)=1,(b,c)=1
(a,b)=1,(a,c)=1,(b,c)=1
2.
(
a
,
b
)
≠
1
,
(
a
,
b
)
≠
1
,
(
b
,
c
)
≠
1
(a,b)\not =1,(a,b)\not=1,(b,c)\not=1
(a,b)=1,(a,b)=1,(b,c)=1
解题思路
一开始没什么思路,题目的要求很繁琐,加上感觉像是容斥,就往容斥的一般思路,求满足反题目条件的数量,然后用总数量减,对于题目要求的两种情况,要考虑三个关系式,比较繁琐。
因为abc调换不影响计数,可以这样构建反问题:
(
a
,
b
)
=
1
,
(
a
,
c
)
≠
1
(a,b)=1,(a,c)\not =1
(a,b)=1,(a,c)=1这样不管bc之间的关系,都是题目的反问题。
但是这样必定会有两个二元组存在相同的状态
(
(
x
,
y
)
≠
1
∣
∣
(
x
,
y
)
=
1
)
( (x,y)\not=1 ||(x,y)=1)
((x,y)=1∣∣(x,y)=1),在计算过程中如果枚举每一个数那就会算两次,最后问题的答案就是:
(
n
3
)
−
r
e
s
2
\binom{n}{3}-\frac {res}{2}
(3n)−2res
对于 a i a_i ai假如{ a n a_n an}中有 x x x个数和 a i a_i ai互质,那么和 a i a_i aigcd不为 1 1 1的数的数量就是 n − x − 1 n-x-1 n−x−1
接下来就是在{
a
n
a_n
an}中求和{a_i}互质的数的数量了,这是一个经典的容斥模型:
可以转化成求:总数减去 和
a
i
{a_i}
ai有公共因子的数
先对每个
a
i
a_i
ai打一个
n
u
m
[
i
]
num[i]
num[i]的表,表示有
n
u
m
[
i
]
num[i]
num[i]个数有因子
i
i
i
然后对每个
a
i
{a_i}
ai唯一分解,由于这里
a
i
<
1
e
5
a_i<1e5
ai<1e5这里的质因子的数量最多不超过
7
7
7个,然后容斥一下,奇减偶加
注意对 r e s res res产生贡献的时候不能出现负数
#include <bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define ll long long
//#define int ll
#define debug cout<<"fuck"<<endl;
#define pb push_back
#define endl '\n'
#define fi first
#define se second
#define db double
#define pii pair<int,int>
#define mp make_pair
const int mod=(int)1e9+7;
const int maxn=(int)1e5+5;
int n;
int a[maxn];
int cnt[maxn];
void init()
{
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=n;i++)
{
for(int j=1;j*j<=a[i];j++)
{
if(a[i]%j==0)
{
cnt[j]++;
if(j!=a[i]/j)cnt[a[i]/j]++;
}
}
}
}
vector<int>v;
int solve(int x)
{
v.clear();
int xx=x;
for(int i=2;i*i<=xx;i++)
{
if(xx%i==0)
{
v.pb(i);
while(xx%i==0)
{
xx/=i;
}
}
}
if(xx>1)v.pb(xx);
int sz=(int)v.size();
int ret=n;
for(int i=1;i<(1<<sz);i++)
{
int cc=0;
int now=1;
for(int j=0;j<sz;j++)
{
if(i&(1<<j))
{
now*=v[j];
cc++;
}
}
if(cc&1)ret-=cnt[now];
else ret+=cnt[now];
}
return ret;
}
int t;
int main()
{
IOS
cin>>t;
while(t--)
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
init();
ll res=(ll)n*(n-1)*(n-2)/6;
ll sum=0;
for(int i=1;i<=n;i++)
{
int num1=solve(a[i]);
//cout<<num1<<endl;
int num2=max(0,n-num1-1);
sum+=(ll)num1*num2;
}
cout<<res-sum/2<<endl;
}
return 0;
}