SDOI 2013 项链 题解

题目传送门

题目大意: 一串合法的项链满足:每颗珠子是一个无序三元组,且三个数都在 [ 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=1Mj=1Mk=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)dM3

二元组方案数类似,为 ∑ d = 1 M μ ( d ) ⌊ M d ⌋ 2 \sum_{d=1}^M\mu(d)\lfloor \frac M d \rfloor^2 d=1Mμ(d)dM2

一元组方案数显然是 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=1nf(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=1nf(gcd(i,n))=dnφ(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(picipici1) 这个式子来求。

剩下的问题是如何求 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)=(m2)f(n1)+(m1)f(n2),第一项表示放一个 与相邻两颗珠子不同的珠子;第二项表示先放一个与第一颗珠子相同的珠子,再放一个与第一颗不同的珠子。

考虑用生成函数求通项公式,令 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 Ff(1)xf(2)x2=(m2)(Ff(1)x)x+(m1)Fx2

由于边界为 f ( 1 ) = 0 , f ( 2 ) = m 2 − m f(1)=0,f(2)=m^2-m f(1)=0,f(2)=m2m,代入然后一顿转化可以得到:
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(m2)x+(1m)x2(m2m)x

这种形式没办法展开,能展开的只有 A 1 − a x \dfrac {A} {1-ax} 1axA 这样的形式,于是我们想要他变成这样子的形式:
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=1axA+1bxB=1(a+b)x+abx2A(1bx)+B(1ax)

观察分母,容易发现 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=m2ab=1m

解得 a = m − 1 , b = − 1 a=m-1,b=-1 a=m1,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(m1)x)A+Ax+B+BxBmx=(m2m)x=m2xmx

因为 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=m2xmx=1m

所以 A = m − 1 A=m-1 A=m1,于是 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(m1)xm11+xm1,展开就是 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((m1)i(1)i(m1))xi,所以 f ( i ) = ( m − 1 ) i − ( − 1 ) i ( m − 1 ) f(i)=(m-1)^i-(-1)^i(m-1) f(i)=(m1)i(1)i(m1)

然后就做完了,但是要注意 n n n 可能为模数的倍数,即 p ∣ n p|n pn,此时没法求 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 pnAns,所以 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);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值