暂无链接
互质2
【题目描述】
Shy 有 n 个数字,要求你从中选一个数和一群数,满足一群数的 GCD>1 且 GCD(一群数的 GCD,一个数的值)=1。问方案数。
【输入】
第一行一个整数 n。
第二行 n 个数表示数组。
【输出】
输出一个数表示答案。(mod 1e9+7)
【输入样例】
3
2 3 2
【输出样例】
5
【提示】
【数据规模】
对于 30%的数据,n≤10;
对于 100%的数据,1≤n≤500000, 2≤数字≤10000000。
题解
linners l i n n e r s 大佬是真的屌,直接A掉,蒟蒻%%%
容易想到直接枚举一群数是不科学的,所以我们尝试枚举
gcd
g
c
d
。
首先,我们处理以
x
x
为因子的数的个数,在这之前我们先开的桶,统计每个数有多少个。显然,对于数
x
x
,都是满足包含因数
x
x
的,所以我们直接枚举暴力累加即可,设最大值为
max
m
a
x
,该过程的复杂度为:
当然,还有更暴力的直接 n−−√ n 枚举因数统计的,不过我们注意到数字的值域是 [2,107] [ 2 , 10 7 ] ,如果使用这种办法稳稳 TLE T L E 。
然后,对于一个因数
x
x
,我们的方案数就是因数为的数排列组合一下再乘以一下其他的数的个数,因为要排除一个数都不选的情况,设因数包含
x
x
的个数为,所以最后的结果为:
其中 2cot[x]−1 2 c o t [ x ] − 1 即为排除全部不选后的选择方案个数(显然),另外,建议预处理 2n 2 n ,面对 107 10 7 的数据快速幂可能不是很妙。
但是,很可能 n−cot[i] n − c o t [ i ] 这一部分的数与 cot[i] c o t [ i ] 里面的数的 gcd g c d 不一定为1,放在这一部分的话不是很好解释,具体证明见分割线以下。
然后,我们这个结果肯定是算重了的,当我们算 gcd=x g c d = x 的时候,很可能其中的数的 gcd g c d 为 2x,3x,...,nx 2 x , 3 x , . . . , n x ,所以我们要从后往前将算重的部分剪掉(想想为什么),这个部分的复杂度也是 O(max×logemax) O ( m a x × l o g e m a x ) 的。
现在已经容斥完毕了,我们只需累加一遍答案即可,总复杂度 O(max×logemax) O ( m a x × l o g e m a x ) , 5000ms 5000 m s 稳过不卡常。
——————————————–分割线————————————————
当然,容斥之神 linners l i n n e r s 是不会满足的。。。
我们注意到,对于
gcd=x
g
c
d
=
x
的方案,会被
d|x
d
|
x
算重,而莫比乌斯函数
μ(x)
μ
(
x
)
正好具有如下性质:
只要在求和的时候乘上 μ(i) μ ( i ) ,就正好就把 x x 及其约数的贡献(即)全部消掉了!跟上面的 O(max×logemax) O ( m a x × l o g e m a x ) 算法是等价的。
但我们的计算是不包括
d=1
d
=
1
的情况的,所以要把
d=1
d
=
1
的情况剔除掉,因为
μ(1)=1
μ
(
1
)
=
1
,所以有:
这样算出来整个 d|x,d≠1 d | x , d ≠ 1 对答案的贡献是 −1 − 1 的(因为 ∑ ∑ 起来是 −1 − 1 ),所以我们最后要取反。
这样,容斥的复杂度变成了 O(max) O ( m a x ) ,大大加快。
那为什么上面计算方案的公式为什么是对的呢?证明如下:
上面讲到了: n−cot[i] n − c o t [ i ] 这一部分的数与 cot[i] c o t [ i ] 里面的数的 gcd g c d 不一定为1,但这一部分被巧妙容斥掉了。
设一群数( cot[i] c o t [ i ] )的 gcd=x g c d = x ,我们选择的数为 y y ,当前枚举的,为了方面描述,我们同时用 x x 表示正在讨论的一群数()的集合,考虑什么时候会计算上面的情况:
1. g|x g | x 且 g|y g | y ,此时想 x x 和被分到了一组,都在我们选择的一群数里面,不会计算;
2. g∤x g ∤ x 且 g∤y g ∤ y ,此时 x,y x , y 都不属于一群数,我们不会同时选择到它们两个;
3. g|x g | x 且 g∤y g ∤ y ,这个时候 x x 被包含进了一群数里,而是我们可能选择到的其他数,于是上面的情况会被计算一次;
4. g∤x g ∤ x 且 g|y g | y ,与上面类似, x x 这个集合被算在了其他数里,被算在了一群数里,上面的情况又被计算一次;
经过上面的讨论,我们可以得到,当且仅当 g g 整除中的一方,而不整除另一方时,上面的不合法方案被计算。
但是,因为有 ∑d1|xμ(d1)=∑d2|yμ(d2)=0 ∑ d 1 | x μ ( d 1 ) = ∑ d 2 | y μ ( d 2 ) = 0 ,即整除 x x 的和为零,整除 y y 的的和为零;又有 ∑d|x,d|yμ(d)=0 ∑ d | x , d | y μ ( d ) = 0 ,即同时整除 x,y x , y 的数的 μ(d) μ ( d ) 之和也是零,根据容斥原理,只整除其中一方的数的 μ μ 之和也为零。
综上,不合法的情况的 μ μ 值之和为零,被消去。因此,本算法正确,由于本算法与上面的暴力容斥原理一致,故两个算法都正确。
代码
代码巨简单 1000− bytesAC 1000 − b y t e s A C 系列。
O(2×(max×logemax+max))
O
(
2
×
(
m
a
x
×
l
o
g
e
m
a
x
+
m
a
x
)
)
运行结果:
#include<bits/stdc++.h>
#define R register int
using namespace std;
const int M=1e7+5,mod=1e9+7;
int n,bak[M],cot[M],p2[M],mx;
void in()
{
R i,a;
scanf("%d",&n);p2[0]=1;
for(i=1;i<=n;++i)p2[i]=p2[i-1]<<1,p2[i]%=mod;
for(i=1;i<=n;++i)scanf("%d",&a),cot[a]++,mx=max(mx,a);
}
void ac()
{
R i,j,ans=0;
for(i=1,j=2;i<=mx;++i,j=i<<1)while(j<=mx)cot[i]+=cot[j],j+=i;
for(i=2;i<=mx;++i)bak[i]=1ll*(p2[cot[i]]-1)*(n-cot[i])%mod;
for(i=mx;i>=2;--i)for(j=2;j*i<=mx;++j)bak[i]=(bak[i]-bak[j*i]+mod)%mod;
for(int i=2;i<=mx;++i)ans+=bak[i],ans%=mod;
printf("%d",ans);
}
int main()
{
in();ac();
return 0;
}
O(3max+max×logemax)
O
(
3
m
a
x
+
m
a
x
×
l
o
g
e
m
a
x
)
运行结果:
#include<bits/stdc++.h>
#define R register int
using namespace std;
const int M=1e7+5,mod=1e9+7;
int n,bak[M],cot[M],p2[M],miu[M],p[M],mx;
bool check[M];
void in()
{
R i,a;
scanf("%d",&n);p2[0]=1;
for(i=1;i<=n;++i)p2[i]=p2[i-1]<<1,p2[i]%=mod;
for(i=1;i<=n;++i)scanf("%d",&a),cot[a]++,mx=max(mx,a);
}
void getmiu()
{
check[1]=1;miu[1]=1;
R i,j,t;
for(i=2;i<=mx;++i)
{
if(!check[i])p[++p[0]]=i,miu[i]=-1;
for(j=1;j<=p[0];++j)
{
t=i*p[j];if(t>mx)break;check[t]=1;
if(i%p[j]==0){miu[t]=0;break;}
miu[t]=-miu[i];
}
}
}
void ac()
{
getmiu();
R i,j,ans=0;
for(i=1,j=2;i<=mx;++i,j=i<<1)while(j<=mx)cot[i]+=cot[j],j+=i;
for(i=2;i<=mx;++i)ans=(1ll*(p2[cot[i]]-1)*(n-cot[i])*miu[i]+ans)%mod;
ans=(-ans)%mod;if(ans<0)ans+=mod;
printf("%d",ans);
}
int main()
{
in();ac();
return 0;
}