[BZOJ 1951] 古代猪文

Link:https://www.lydsy.com/JudgeOnline/problem.php?id=1951

 

Solution:

见过最长的数论题题面.......

 

一道数论的综合题,求解:

\[g^{\sum_{d|n} C_n^d}~mod~p\]

 

我们先看幂能否化简,

由费马小定理可知

\begin{aligned} \displaystyle ans &=  g^{\sum_{d|n} C_n^d}~mod~p  \\  &=g^{\sum_{d|n} C_n^d~mod~(p-1)}~mod~p  \end{aligned}

 

对于化简后的幂:

\[\sum_{d|n} C_n^d~mod~(p-1)\]

我们想到枚举每一个n的约数,使用Lucas定理求大组合数取模

 

但P-1=2*3*4679*35617,不是一个质数

于是我们以每一个质因子为模数算出最终的解

由于质因子之间是互质的,再用中华剩余定理合并结果算出最小的\[\sum_{d|n} C_n^d\],即为\[\sum_{d|n} C_n^d~mod~(p-1)\]

 

Code:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int MAXN=1e5+10;
const int MOD=999911659;

int quick_pow(ll a,ll b,int p) //快速幂
{
    ll ret=1;a%=p; while(b) { if(b&1) ret=ret*a%p; b>>=1;a=a*a%p; } return ret; } int inv(ll a,int p){return quick_pow(a,p-2,p);} //求逆元 int g,n,fac[4][MAXN],c[4]; int pri[]={2,3,4679,35617}; int C(int n,int m,int p) //求组合数 { if(n>m) return 0; return 1ll*fac[p][m]*inv(1ll*fac[p][n]*fac[p][m-n],pri[p])%pri[p]; } int Lucas(int n,int m,int p) //Lucas定理 { if(m==0) return 1; return C(n%pri[p],m%pri[p],p)*Lucas(n/pri[p],m/pri[p],p)%pri[p]; } ll CRT() //中国剩余定理 { ll ret=0,p=MOD-1; for(int i=0;i<4;i++) ret=(ret+1ll*p/pri[i]*inv(p/pri[i],pri[i])*c[i])%p; return ret%MOD; } int main() { cin >> n >> g; if(g==MOD) return cout << 0,0; for(int i=0;i<4;i++) //预处理阶乘 { fac[i][0]=1; for(int j=1;j<=pri[i];j++) fac[i][j]=fac[i][j-1]*j%pri[i]; } for(int i=0;i<4;i++) for(int j=1;j*j<=n;j++) if(n%j==0) { c[i]=(c[i]+Lucas(j,n,i))%pri[i]; if(j*j!=n) c[i]=(c[i]+Lucas(n/j,n,i))%pri[i]; } cout << quick_pow(g,CRT(),MOD); return 0; }

 

Review:

1、如果模数为质数,

利用费马小定理对幂化简

 

2、遇到大组合数取模  ------->   Lucas定理

 

如果模数不为质数,质因数分解后分别求出结果再用中华剩余定理合并,套路啊……

 

3、中华剩余定理求解方法

(1)递推式地两两求解

(2)根据推导出的结论直接求解:

\[x=(\sum\limits_{i=1}^k c_i*{M\over m_i}*inv({M\over m_i},mi))\%M\]

转载于:https://www.cnblogs.com/newera/p/9088919.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值