题目链接:哆啦A梦传送门
题意:给出长度为n的序列a,找出长度也为n的序列b,
满足
b
i
≤
a
i
,
g
c
d
(
b
1
,
b
2
,
.
.
.
,
b
n
)
≥
2
b_i\leq a_i,gcd(b_1,b_2,...,b_n)\geq 2
bi≤ai,gcd(b1,b2,...,bn)≥2,问:有多少种不同的序列b?
题解:
我们先设:
f
(
d
)
f(d)
f(d)为满足
g
c
d
(
b
1
,
b
2
,
.
.
.
,
b
n
)
=
d
gcd(b_1,b_2,...,b_n)=d
gcd(b1,b2,...,bn)=d的方案数。
那么我们根据莫比乌斯第二描述:
F
(
n
)
=
∑
n
∣
d
f
(
d
)
F(n)=\sum_{n|d}f(d)
F(n)=n∣d∑f(d)
f
(
n
)
=
∑
n
∣
d
u
(
d
n
)
∗
F
(
d
)
f(n)=\sum_{n|d}u(\frac{d}{n})*F(d)
f(n)=n∣d∑u(nd)∗F(d)
易得: F ( n ) F(n) F(n)为满足 d ∣ g c d ( b 1 , b 2 , . . . , b n ) d|gcd(b_1,b_2,...,b_n) d∣gcd(b1,b2,...,bn)的方案数。
参考博客:(https://blog.csdn.net/V5ZSQ/article/details/76381584)
即:
F
(
d
)
=
∏
i
=
1
m
i
⌊
a
i
d
⌋
\begin{aligned}F(d)=\prod_{i=1}^{mi} \lfloor \frac{a_i}{d}\rfloor \end{aligned}
F(d)=i=1∏mi⌊dai⌋ ,显然这样求复杂度有点大,我们再设
s
u
m
[
i
]
表
示
a
i
≤
i
的
总
数
sum[i]表示a_i \leq i的总数
sum[i]表示ai≤i的总数,对于每个d,
它在每一段
a
∈
(
i
∗
d
−
1
,
(
i
+
1
)
∗
d
−
1
)
a\in(i*d-1,(i+1)*d-1)
a∈(i∗d−1,(i+1)∗d−1) (
i
∗
d
≤
1
e
5
i*d\leq 1e5
i∗d≤1e5)的值除d的值都是一样的,都为i。那么我们只需算下它们的幂
i
s
u
m
[
(
i
+
1
)
∗
d
−
1
]
−
s
u
m
[
i
∗
d
−
1
]
i^{sum[(i+1)*d-1]-sum[i*d-1]}
isum[(i+1)∗d−1]−sum[i∗d−1]就好了。
那么此题的结果就为:
a n s = F ( 1 ) − f ( 1 ) = F ( 1 ) − ∑ d = 1 m i F ( d ) = − ∑ d = 2 m i F ( d ) \begin{aligned} ans&=F(1)-f(1)\\ &=F(1)-\sum_{d=1}^{mi}F(d)\\ &=-\sum_{d=2}^{mi}F(d) \end{aligned} ans=F(1)−f(1)=F(1)−d=1∑miF(d)=−d=2∑miF(d)
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e5+10;
const LL mod=1e9+7;
int prime[N],tot,mu[N];
bool vis[N];
void init()
{
mu[1]=1;
for(int i=2;i<N;i++)
{
if(!vis[i]){
prime[++tot]=i;
mu[i]=-1;
}
for(int j=1;j<=tot&&i*prime[j]<N;j++){
int x=i*prime[j];
vis[x]=1;
if(i%prime[j]==0){
mu[x]=0;
break;
}
mu[x]=-mu[i];
}
}
}
int sum[N];
LL F[N];
LL fast(LL x,LL y)
{
LL re=1;
while(y)
{
if(y&1) re=re*x%mod;
x=x*x%mod;
y>>=1;
}
return re;
}
int main()
{
init();
int n,T=0;
int ncase;
scanf("%d",&ncase);
while(ncase--){
int n;
scanf("%d",&n);
int mi=1e5,item;
memset(sum,0,sizeof(sum));
for(int i=1;i<=n;i++){
scanf("%d",&item);
mi=min(item,mi);
sum[item]++;
}
for(int i=1;i<=1e5;i++){
sum[i]+=sum[i-1];
}
for(int d=2;d<=mi;d++)
{
F[d]=1LL;
for(int i=1;i*d<=100000;i++){
F[d]=F[d]*fast(i,sum[min((i+1)*d-1,100000)]-sum[i*d-1])%mod;
// printf("%d %d %d %d\n",i,d,mi,F[d]);
}
}
LL ans=0;
for(int d=2;d<=mi;d++)
{
ans=ans-mu[d]*F[d]+mod;
ans%=mod;
}
printf("Case #%d: %lld\n",++T,ans);
}
return 0;
}