题面
定义一个珠子为无序三元组 (x,y,z),0<x,y,z≤a,gcd(x,y,z)=1。
定义一个项链为一个 n 个珠子组成的环,相邻的珠子不相同。
求有多少本质不同(经过旋转能完全相同的定义为本质相同)的项链。多测,n≤1014,a≤107,T≤10。
题解
因为“项链”的要求只需要相邻珠子不同,不要求珠子上的数字有什么别的关系,所以这个题是完全割裂的两个问题:
- 怎么求珠子的数量?
- 已知珠子的数量,怎么求合法的项链的数量?
珠子数量
定义一个珠子为一个无序三元组 (x,y,z),满足 0<x,y,z⩽a,且 gcd(x,y,z)=1。
给定 a,求有多少种珠子。
互质这个条件就显得非常数论,然而一般的数论枚举是有序的,因此转化为有序问题:
- 若 x=y=z,设有序三元组数量为 a,则无序三元组数量为 3!a=6a。
- 若有两个元素相同,设有序三元组数量为 a,则无序三元组数量为 A32a=3a。
- 若 x=y=z,因为三个数要互质,显然只有 (1,1,1) 符合条件。
先考虑考虑第二个怎么算:
cnt2=−3+3i=1∑aj=1∑a[gcd(i,j)=1]
莫反人 DNA 已经动了:
−3+3i=1∑aj=1∑ad∣gcd(i,j)∑μ(d)
然后换 ∑:
−3+3d=1∑aμ(d)⌊da⌋2
第一个?同理即可,不多赘述:
cnt1=−1−cnt2+d=1∑aμ(d)⌊da⌋3
于是这一部分答案为 6cnt1+3cnt2+1。
项链数量
有 m 种互不相同的珠子,每种无限个。求可以串成多少种本质不同的大小为 n 的项链,要求相邻珠子不同种。
两个项链本质相同,当且仅当其旋转后相同。
“本质不同的项链”非常的群论,我们考虑枚举循环节,设 fi 表示循环节个数为 i 时,不动点的数量:
ans=i=1∑nf(gcd(i,n))=n1d∣n∑φ(dn)f(d)
考虑 fi 的现实意义:大小为 i 的合法项链的染色的方案数。考虑如何递推:对于一个大小为 n−1 的合法项链,枚举一个断点,加入一个和两边颜色都不同的珠子;或者对于一个大小为 n−2 的合法项链,先加入一个和一边颜色相同的珠子,然后在两个珠子之间加一个不同的颜色劈开。(因为项链是合法的,因此这两种统计不重):
fn=(m−2)fn−1+(m−1)fn−2
边界 f1=0,f2=m(m−1)。看 n 的范围 1014,线性递推就算了吧。因为本人太菜不会常系数齐次线性递推,只能带大家用生成函数乱搞一下。怎么用生成函数求通项公式?写出 OGF、代入递推式(注意边界系数)、求出封闭形式、换另一种方法展开。
我们写出 fi 的 OGF:
F(x)=i=1∑∞fixi
根据递推式得到:
F(x)=x(m−2)F(x)+x2(m−1)F(x)+x2f2+xf1
整理,将 f1=0,f2=m(m−1) 代入:
F(x)=1−(m−2)x−(m−1)x2x2m(m−1)
如何展开?不妨待定系数法,设待定系数 A,B,a,b 满足:
1−axAx+1−bxBx=1−(m−2)x−(m−1)x2x2m(m−1)
整理得到:
1−(a+b)x+abx2(A+B)x−(Ab+aB)x2=1−(m−2)x−(m−1)x2x2m(m−1)
于是得到:
⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧A+B=0Ab+aB=−m(m−1)a+b=m−2ab=−(m−1)
可以先解出 a,b,由第三个式子,b=m−a−2,代入第四个式子解一元二次方程:
−a2−(2−m)a+m−1=0
解二次方程都会吧,因为 m⩾0,容易解得 a1=m−1,a2=−1。不妨令 a=m−1,b=−1。
{A+B=0−A+(m−1)B=m−m2
解二元一次方程都会吧,容易解得 A=m−1,B=1−m。
F(x)=x(1−axA+1−bxB)=x(1−(m−1)xm−1+1−(−1)x1−m)
比值为 p 的等比数列的生成函数为 G(x)=1−px1,因此拆开化简一下:
i⩾1∑xi[(m−1)i+(−1)i(m−1)]
因此这个序列的通项公式为:
fn=(m−1)n+(−1)n(m−1)
又因为:
ans=n1d∣n∑φ(dn)f(d)
于是这个部分也完成了。
细节
细节很多,调了一个上午,看题解才豁然开朗。
- 写这种题就是要像生产队的驴一样——多磨(模)。
- n 可能是模数的倍数,不能直接乘以 n。可以考虑先在模 mod2 意义下求解,最后在转化为模 109+7 的答案。如果你 WA on #3 读到 0,就是这个原因。
- 用上述方法时要么龟速乘要么
__in128
,像我这种懒人当然选择 __128
了。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
| #include<bits/stdc++.h> #define int __int128 using namespace std; const int max_n=10000001,MOD=1000000007;int mod; inline int read(){ int x=0;bool w=0;char c=getchar(); while(c<'0' || c>'9') w|=c=='-',c=getchar(); while(c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return w?-x:x; } inline void write(int x){ if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10^48); } inline int mi(int a,int p=mod-2){ int res=1; while(p){ if(p&1) res=res*a%mod; a=a*a%mod,p>>=1; } return res; } struct par{ int x,y; }; inline par makep(int a,int b){ par res; res.x=a,res.y=b; return res; }
int n,m,iv6,iv62=833333345000000041LL,iv;
signed pr[max_n/10],mu[max_n],cntp; bool isp[max_n];
inline void Getprime(int n){ memset(isp,1,sizeof(isp)),isp[1]=0; mu[1]=1; for(register int i=2;i<=n;++i){ if(isp[i]){ pr[++cntp]=i, mu[i]=-1; } for(register int j=1;j<=cntp && i*pr[j]<=n;++j){ isp[i*pr[j]]=0; if(i%pr[j]==0){ mu[i*pr[j]]=0; break; } mu[i*pr[j]]=-mu[i]; } } for(register int i=1;i<=n;++i) mu[i]=mu[i-1]+mu[i]; }
inline int F(int n){ return (mi(m-1,n)+(n&1?mod-1:1)*(m-1)%mod)%mod; }
int cnt1,cnt2;
inline int sub1(int a){ cnt1=cnt2=0; for(register int l=1,r,k;l<=a;l=r+1){ r=(a/(a/l)),k=a/l; cnt2=(cnt2+(int)(mu[r]-mu[l-1])*k*k)%mod, cnt1=(cnt1+(int)(mu[r]-mu[l-1])*k*k%mod*k)%mod; } cnt1=(cnt1%mod+mod)%mod, cnt2=(cnt2%mod+mod)%mod;
cnt2=(mod-3+3*cnt2)%mod, cnt1=(mod-1-cnt2+cnt1)%mod; return (iv6*cnt1+iv6*2*cnt2+1)%mod; }
int lim,ans; vector<par> pfac;
inline void fact(int n){ pfac.resize(0); for(register int i=1;i<=cntp && pr[i]*pr[i]<=n;++i) if(n%pr[i]==0){ int k=0; while(n%pr[i]==0) n/=pr[i],++k; pfac.push_back(makep(pr[i],k)); } if(n>1) pfac.push_back(makep(n,1)); lim=pfac.size(); }
inline void dfs(int l,int a,int phi){ if(l==lim){ ans=(ans+phi*F(n/a))%mod; return; } dfs(l+1,a,phi); for(register int i=1;i<=pfac[l].y;++i){ a=a*pfac[l].x; phi=phi*(i==1?pfac[l].x-1:pfac[l].x)%mod; dfs(l+1,a,phi); } }
inline int sub2(){ ans=0,fact(n); dfs(0,1,1); return ans%mod; }
signed main(){ mod=MOD,Getprime(10000000),iv=iv6=mi(6); for(register int T=read();T>0;--T){ n=read();bool ok=0; if(n%MOD==0) mod=MOD*MOD,iv6=iv62; else mod=MOD,ok=1,iv6=iv; m=sub1(read()); int ans=sub2(); if(!ok) write(ans/MOD*mi(n/MOD)%MOD); else write(ans*mi(n%MOD)%MOD); putchar('\n'); } return 0; }
|