题目大意: 一串合法的项链满足:每颗珠子是一个无序三元组,且三个数都在 [ 1 , M ] [1,M] [1,M] 范围内,它们的 gcd = 1 \gcd=1 gcd=1;相邻的珠子一定不同。另外,如果一串项链能够通过旋转得到另一串项链,那么认为他们是相同的。问有多少种不同的项链。
题解
容易发现其实题目分为几乎不相关的两部分:求珠子数量;求项链数量。
第一部分
无序不太好求,转化为求有序三元组数量然后去重,即:三个数互不相同
/
6
+
/6+
/6+两个数相同
/
3
+
/3+
/3+三个数都相同
,容斥一下变成:三元组方案数
/
6
+
/6+
/6+二元组方案数
×
1
2
+
\times\dfrac 1 2+
×21+一元组方案数
×
1
3
\times\dfrac 1 3
×31,即
(
(
(三元组方案数
+
+
+二元组方案数
×
3
+
\times 3+
×3+一元组方案数
×
2
)
/
6
\times 2)/6
×2)/6。
三元组方案数为 ∑ i = 1 M ∑ j = 1 M ∑ k = 1 M [ gcd ( i , j , k ) = 1 ] \sum_{i=1}^M\sum_{j=1}^M\sum_{k=1}^M[\gcd(i,j,k)=1] ∑i=1M∑j=1M∑k=1M[gcd(i,j,k)=1],根据莫反套路转成 ∑ d = 1 M μ ( d ) ⌊ M d ⌋ 3 \sum_{d=1}^M\mu(d)\lfloor \frac M d \rfloor^3 ∑d=1Mμ(d)⌊dM⌋3。
二元组方案数类似,为 ∑ d = 1 M μ ( d ) ⌊ M d ⌋ 2 \sum_{d=1}^M\mu(d)\lfloor \frac M d \rfloor^2 ∑d=1Mμ(d)⌊dM⌋2。
一元组方案数显然是 1 1 1,只有 1 1 1 满足 gcd = 1 \gcd=1 gcd=1。
此时我们求出了不同的珠子个数为 m m m。
第二部分
显然求不同的环数需要套一手
burnside
\text{burnside}
burnside 引理,问题变成求每个置换的不动点数量。对于一个长度为
i
i
i 的置换,循环数显然是
gcd
(
i
,
n
)
\gcd(i,n)
gcd(i,n),每个循环内要求珠子一样,但是又要求相邻的珠子不能一样,即相邻的循环珠子不能一样,于是令
f
(
n
)
f(n)
f(n) 表示长度为
n
n
n 的项链,相邻珠子不同,有多少种方案,则答案为:
1
n
∑
i
=
1
n
f
(
gcd
(
i
,
n
)
)
\frac 1 n\sum_{i=1}^n f(\gcd(i,n))
n1i=1∑nf(gcd(i,n))
注意, f ( n ) f(n) f(n) 求的项链数不考虑旋转,即 A A A 就算能旋转得到 B B B,也不认为是一样的方案,这样定义的原因比较显然,因为此时我们在求不动点数。
但是这样没法求解,设
d
=
gcd
(
i
,
n
)
d=\gcd(i,n)
d=gcd(i,n),考虑枚举
d
d
d,然后求有多少个
i
i
i 满足
gcd
(
i
,
n
)
=
d
\gcd(i,n)=d
gcd(i,n)=d,这样的
i
i
i 可以表示为
i
=
d
k
i=dk
i=dk,其中
gcd
(
n
d
,
k
)
=
1
\gcd(\frac n d,k)=1
gcd(dn,k)=1,所以满足要求的
k
k
k 有
φ
(
n
d
)
\varphi(\frac n d)
φ(dn) 个,于是可以得到:
∑
i
=
1
n
f
(
gcd
(
i
,
n
)
)
=
∑
d
∣
n
φ
(
n
d
)
f
(
d
)
\sum_{i=1}^n f(\gcd(i,n))=\sum_{d|n} \varphi(\frac n d)f(d)
i=1∑nf(gcd(i,n))=d∣n∑φ(dn)f(d)
其中, φ \varphi φ 不能用筛法求,但是可以用 φ ( n ) = ∏ i = 1 k ( p i c i − p i c i − 1 ) \varphi(n)=\prod_{i=1}^k (p_i^{c_i}-p_i^{c_i-1}) φ(n)=∏i=1k(pici−pici−1) 这个式子来求。
剩下的问题是如何求 f f f,考虑往项链末尾放珠子,不难发现 f f f 满足这个递推式: f ( n ) = ( m − 2 ) f ( n − 1 ) + ( m − 1 ) f ( n − 2 ) f(n)=(m-2)f(n-1)+(m-1)f(n-2) f(n)=(m−2)f(n−1)+(m−1)f(n−2),第一项表示放一个 与相邻两颗珠子不同的珠子;第二项表示先放一个与第一颗珠子相同的珠子,再放一个与第一颗不同的珠子。
考虑用生成函数求通项公式,令
F
(
x
)
=
∑
i
=
0
f
(
i
)
x
i
F(x)=\sum_{i=0}f(i)x^i
F(x)=∑i=0f(i)xi,将递推式写成封闭形式:
F
−
f
(
1
)
x
−
f
(
2
)
x
2
=
(
m
−
2
)
(
F
−
f
(
1
)
x
)
x
+
(
m
−
1
)
F
x
2
F-f(1)x-f(2)x^2=(m-2)(F-f(1)x)x+(m-1)Fx^2
F−f(1)x−f(2)x2=(m−2)(F−f(1)x)x+(m−1)Fx2
由于边界为
f
(
1
)
=
0
,
f
(
2
)
=
m
2
−
m
f(1)=0,f(2)=m^2-m
f(1)=0,f(2)=m2−m,代入然后一顿转化可以得到:
F
=
(
m
2
−
m
)
x
1
−
(
m
−
2
)
x
+
(
1
−
m
)
x
2
F=\frac {(m^2-m)x} {1-(m-2)x+(1-m)x^2}
F=1−(m−2)x+(1−m)x2(m2−m)x
这种形式没办法展开,能展开的只有
A
1
−
a
x
\dfrac {A} {1-ax}
1−axA 这样的形式,于是我们想要他变成这样子的形式:
F
=
A
1
−
a
x
+
B
1
−
b
x
=
A
(
1
−
b
x
)
+
B
(
1
−
a
x
)
1
−
(
a
+
b
)
x
+
a
b
x
2
F=\frac A {1-ax}+\frac B {1-bx}=\frac {A(1-bx)+B(1-ax)} {1-(a+b)x+abx^2}
F=1−axA+1−bxB=1−(a+b)x+abx2A(1−bx)+B(1−ax)
观察分母,容易发现
a
,
b
a,b
a,b 满足:
{
a
+
b
=
m
−
2
a
b
=
1
−
m
\begin{cases} a+b=m-2\\ ab=1-m \end{cases}
{a+b=m−2ab=1−m
解得
a
=
m
−
1
,
b
=
−
1
a=m-1,b=-1
a=m−1,b=−1,代入到分子里,考虑求出
A
,
B
A,B
A,B:
A
(
1
+
x
)
+
B
(
1
−
(
m
−
1
)
x
)
=
(
m
2
−
m
)
x
A
+
A
x
+
B
+
B
x
−
B
m
x
=
m
2
x
−
m
x
\begin{aligned} A(1+x)+B(1-(m-1)x)&=(m^2-m)x\\ A+Ax+B+Bx-Bmx&=m^2x-mx \end{aligned}
A(1+x)+B(1−(m−1)x)A+Ax+B+Bx−Bmx=(m2−m)x=m2x−mx
因为
A
,
B
A,B
A,B 中不含
x
x
x,而等式右边每一项都有
x
x
x,于是可以知道
A
+
B
=
0
A+B=0
A+B=0,即
A
,
B
A,B
A,B 互为相反数,带上去消一下就可以得到:
−
B
m
x
=
m
2
x
−
m
x
B
=
1
−
m
\begin{aligned} -Bmx&=m^2x-mx\\ B&=1-m \end{aligned}
−BmxB=m2x−mx=1−m
所以 A = m − 1 A=m-1 A=m−1,于是 F = m − 1 1 − ( m − 1 ) x − m − 1 1 + x F=\dfrac {m-1} {1-(m-1)x}-\dfrac {m-1} {1+x} F=1−(m−1)xm−1−1+xm−1,展开就是 F = ∑ i = 0 ( ( m − 1 ) i − ( − 1 ) i ( m − 1 ) ) x i F=\sum_{i=0} ((m-1)^i-(-1)^i(m-1))x^i F=∑i=0((m−1)i−(−1)i(m−1))xi,所以 f ( i ) = ( m − 1 ) i − ( − 1 ) i ( m − 1 ) f(i)=(m-1)^i-(-1)^i(m-1) f(i)=(m−1)i−(−1)i(m−1)。
然后就做完了,但是要注意 n n n 可能为模数的倍数,即 p ∣ n p|n p∣n,此时没法求 n n n 的逆元。
考虑以 p 2 p^2 p2 作为模数,那么 n n n 的逆元相当于 n p \dfrac n p pn 在模 p p p 意义下的逆元,这样就可以求出逆元了。但此时 A n s Ans Ans 乘逆元求出来的是模 p 2 p^2 p2 意义下的解,由于 A n s Ans Ans 是 n n n 的倍数,即 p ∣ n ∣ A n s p|n|Ans p∣n∣Ans,所以 A n s Ans Ans 可以直接除以 p p p 得到模 p p p 意义下的答案。
代码如下:
#include <cstdio>
#include <algorithm>
using namespace std;
#define maxn 10000010
#define ll long long
int T;
ll n,M,m,mod,Type;
const ll Mod1=1000000007,Mod2=1000000014000000049ll;
const ll inv61=166666668,inv62=833333345000000041ll;
int prime[maxn],pt=0,mu[maxn];
bool v[maxn];
void SieveInit(){
mu[1]=1;
for(int i=2;i<=maxn-10;i++){
if(!v[i])prime[++pt]=i,mu[i]=-1;
for(int j=1;j<=pt&&i*prime[j]<=maxn-10;j++){
v[i*prime[j]]=true;
if(i%prime[j]==0)break;
mu[i*prime[j]]=-mu[i];
}
mu[i]+=mu[i-1];
}
}
ll Mul(ll x,ll y){
if(!Type)return x*y%mod;
else return (x*y-(ll)(((long double)x*y+0.5)/((long double)mod))*mod+mod)%mod;
}
void solve_m(){
m=2;
for(int l=1,r;l<=M;l=r+1){
r=M/(M/l);
m=(m+Mul(Mul(Mul(M/l,M/l),M/l+3),(mu[r]-mu[l-1]+mod)%mod))%mod;
}
m=Mul(m,!Type?inv61:inv62);
}
ll ksm(ll x,ll y){ll re=1;for(;(y&1?re=Mul(re,x):0),y;y>>=1,x=Mul(x,x));return re;}
ll inv(ll x){x%=Mod1;ll y=Mod1-2,re=1;for(;(y&1?re=1ll*re*x%Mod1:0),y;y>>=1,x=1ll*x*x%Mod1);return re;}
ll yz[50],cnt[50],t=0,ans;
ll f(ll x){return (ksm(m-1,x)+(x&1?mod-m+1:m-1))%mod;}
void dfs(int x,ll now,ll phi){
if(x>t){
ans=(ans+Mul(phi%mod,f(n/now)))%mod;
return;
}
for(int i=0;i<=cnt[x];i++){
dfs(x+1,now,phi);
now*=yz[x];
phi*=i==0?yz[x]-1:yz[x];
}
}
void solve(){
ans=t=0;ll N=n;
for(ll i=2;i*i<=N;i++)if(N%i==0){
yz[++t]=i;cnt[t]=0;
while(N%i==0)N/=i,cnt[t]++;
}
if(N>1)yz[++t]=N,cnt[t]=1;
dfs(1,1,1);
}
int main()
{
SieveInit();
scanf("%d",&T);while(T--)
{
scanf("%lld %lld",&n,&M);
if(n%Mod1)mod=Mod1,Type=0;
else mod=Mod2,Type=1;
solve_m();solve();
if(!Type)ans=ans*inv(n%Mod1)%Mod1;
else ans=ans/Mod1*inv(n/Mod1)%Mod1;
printf("%lld\n",ans);
}
}