古代猪文[题解]
古代猪文
题目大意
给定整数 \(n\) 、\(g\) , \((1\leq,n\leq10^9)\) ,要求计算 \(g^{\sum_{k|n}C_n^k} mod\) \(999911659\) \((\) \(k\) 是指 \(n\) 的正约数\()\)
题目分析
抛开前面一大段的废话,我们会发现从 \(n\) 个文字中保留下 \(n/k\) 个的情况数其实就是组合数 \(C_n^{n/k}\) 的值,这不难解释。又因为如果 \(k\) 是 \(n\) 的正约数,那么 \(n/k\) 肯定也是 \(n\) 的正约数,而由题意正约数为 \(n/k\) 时,方案数就为 \(C_n^k\)。同时,若为 \(k\times k=n\)的特殊情况,因为 \(n/k=k\) 易得其组合数为 $C_n^k $ 。题目中的 \(p\) 是所有这些组合数加起来,我们可以考虑把上述的 \(k\) 和 \(n/k\) 的情况数交换位置,最后易证 \(p=\sum_{k|n}C_n^k\) 的正确性。
一个特判
若 \(g=999911659\) ,则上式结果显然为零,不做过多解释。
求解 \(p\)
若 \(g\neq999911659\) ,则由欧拉定理的推论可得 \(g^{\sum_{k|n}C_n^k} mod \equiv g^{\sum_{k|n}C_n^k mod 999911658}\) \((mod\) \(999911659)\)
欧拉定理的推论:若正整数 \(a,n\) 互质,则对于任意正整数 \(b\) ,有 \(a^b \equiv a^{b mod\varphi(n)}\) \((mod\) \(n)\)。其中,\(\varphi\) 为欧拉函数
因此,本题即求解 \(\sum_{k|n}C_n^k mod\) $ 999911658$
我们会发现,这个式子并不好求,尝试对模数分解质因数,得到 \(999911658=2 \times 3 \times 4679 \times 35617\)。这种数被称之为 \(square-free-number\) ,其所有质因子的指数都为 \(1\)。
我们可以枚举 \(n\) 的约数 \(k\),然后直接使用 \(Lucas\) 定理求解组合数 \(C^n_k\) ,再分别计算出 \(\sum_{k|n}C_n^k\) 对 \(2\)、\(3\)、\(4679\)、\(35617\) 四个质数取模的结果,记为 \(a1\)、\(a2\)、\(a3\)、\(a4\)。
\(Lucas\)定理:若 \(p\) 是质数,则对于任意整数 \(1\leq m\leq n\) ,有:\(C_n^m\equiv C_{n mod p}^{m mod p}\times C_{n/p}^{m/p}\) \((mod\) \(p)\)
inline ll C(ll n,ll m,ll P) //组合数求解方法之一
{
ll a=1,b=1;
for(int i=n-m+1;i<=n;i++)
a=(a*i)%P;
for(int i=2;i<=m;i++)
b=(b*i)%P;
return (a*power(b,P-2,P))%P;
}
inline ll Lucas(ll x,ll y,ll P) //Lucas定理
{
if(!y) return 1;
if(x<y) return 0;
if(x<P&&y<P) return C(x,y,P);
return (Lucas(x%P,y%P,P)*Lucas(x/P,y/P,P))%P;
}
最后,用中国剩余定理求解线性同余方程组:
-
\(x\) \(mod\) \(2\) \(=\) \(a1\)
-
\(x\) \(mod\) \(3\) \(=\) \(a2\)
-
\(x\) \(mod\) \(4679\) \(=\) \(a3\)
-
\(x\) \(mod\) \(35617\) \(=\) \(a4\)
中国剩余定理:
即可得到 \(\sum_{k|n}C_n^k mod\) $ 999911658$ 的最小非负整数解 \(x\) 。再用快速幂即可得到答案。
总结
这是组合数学一道非常经典的题目,涉及到欧拉定理、\(Lucas\) 定理、中国剩余定理以及组合数的求解多方面知识,是一道不可多得的好题。
CODE
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100010;
ll n,g;
ll a1,a2,a3,a4;
int cnt,d[N];
inline ll power(ll x,ll k,ll P)
{
ll res=1;
while(k){
if(k&1) res=(res*x)%P;
k>>=1;
x=(x*x)%P;
}
return res%P;
}
inline ll C(ll n,ll m,ll P) //组合数求解方法之一
{
ll a=1,b=1;
for(int i=n-m+1;i<=n;i++)
a=(a*i)%P;
for(int i=2;i<=m;i++)
b=(b*i)%P;
return (a*power(b,P-2,P))%P;
}
inline ll Lucas(ll x,ll y,ll P) //Lucas定理
{
if(!y) return 1;
if(x<y) return 0;
if(x<P&&y<P) return C(x,y,P);
return (Lucas(x%P,y%P,P)*Lucas(x/P,y/P,P))%P;
}
int main()
{
scanf("%lld%lld",&n,&g);
if(g%999911659==0) { printf("0\n"); return 0; } //特判
for(int i=1;i*i<=n;i++){ //求解n的正约数
if(i*i==n) d[++cnt]=n/i;
else if(n%i==0) d[++cnt]=i,d[++cnt]=n/i;
}
//求解a1、a2、a3、a4
for(int i=1;i<=cnt;i++)
a1=(a1+Lucas(n,d[i],2))%2;
for(int i=1;i<=cnt;i++)
a2=(a2+Lucas(n,d[i],3))%3;
for(int i=1;i<=cnt;i++)
a3=(a3+Lucas(n,d[i],4679))%4679;
for(int i=1;i<=cnt;i++)
a4=(a4+Lucas(n,d[i],35617))%35617;
ll P=999911658;
ll ans=(a1*P/2*power(P/2,2-2,2))%P+(a2*P/3*power(P/3,3-2,3))%P+(a3*P/4679*power(P/4679,4679-2,4679))%P+(a4*P/35617*power(P/35617,35617-2,35617))%P; //中国剩余定理
ans=((ans%P)+P)%P;
printf("%lld\n",power(g,ans,P+1));
return 0;
}