古代猪文[题解]

古代猪文

题目大意

给定整数 \(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;
}
posted @ 2021-03-03 22:15  ╰⋛⋋⊱๑落叶๑⊰⋌⋚╯  阅读(93)  评论(0编辑  收藏  举报