P2480 SDOI 古代豬文(自帶其他詳細基礎數論)
P2480 SDOI2010古代豬文
題目大意:求
\(G^{\sum_{d|n}{n \choose d}}~mod~999911659\)
各種基礎數論全家桶,做這個題相當於複習今天內容了
999911659為質數
費馬小定理\(a^p\equiv a(mod~p)\),\(a^p~mod~p=a~mod~p\)
\(p是質數時,φ(p)=p-1,根據尤拉定理推論a^b\equiv a^{b~mod~φ(n)}=a^{b~mod~(p-1)}(mod~n)\)
化簡可得\(a^{\sum d|nC_n^d~mod~999911658}mod999911659\)
質因數分解\(999911658 = 2*3*4679*35617\)
\(列舉每個d,再用個Lucas定理或其他鬼方法把C_n^d算出來,分別計算\sum C_n^d對四個質數取模結果記為a_1,a_3,a_3,a_4\)
跑箇中國剩餘定理
中國剩餘定理:\(m_i是兩兩互質的整數,m=\prod_{i=1}^nm_i,M_i=m/m_i,t_i\)是線性同餘方程\(M_it_i\equiv1(mod~m_i)\)
的一個解,對於任意的n個整數\(a_i\),方程組有整數解為\(x=\sum_{i=1}^na_iM_it_i\)
\[\left\{ \begin{aligned} x & \equiv a_1(mod~2) \\ x & \equiv a_2(mod~3) \\ x&\equiv a_3(mod~4679)\\ x&\equiv a_4(mod~35617)\\ \end{aligned} \right. \]
#include<cstdio> #define maxn #define mod 999911658 #define int long long using namespace std; int n,G,jc[40000],a[5],b[5]={0,2,3,4679,35617},ans; inline int qpow(int a,int k,int p) { int res=1; while(k) { if(k&1) res=(res*a)%p; a=(a*a)%p; k>>=1; } return res%p; } void jiecheng(int p){ jc[0] = 1; for(int i = 1;i<=p;i++) jc[i] = jc[i-1] * i % mod; } int C(int n,int m,int p){ if(n < m) return 0; return jc[n] * qpow(jc[m],p-2,p) % p * qpow(jc[n-m],p-2,p) % p; } int lucas(int n,int m,int p){ if(n<m) return 0;if(!n) return 1; return lucas(n/p,m/p,p)*C(n % p,m % p,p) % p; } void zgsy(){ for(int i=1;i<=4;i++) ans=(ans+a[i]*(mod/b[i])%mod*qpow(mod/b[i],b[i]-2,b[i]))%mod; } signed main(){ scanf("%lld%lld",&n,&G); if(G%(mod+1)==0){ printf("0\n"); return 0; }//特判 for(int k=1;k<=4;k++){ jiecheng(b[k]); for(int i=1;i*i<=n;i++){ if(n%i==0){ a[k]=(a[k]+lucas(n,i,b[k]))%b[k]; if(i*i!=n){ a[k]=(a[k]+lucas(n,n/i,b[k]))%b[k]; } } } }//逐一列舉n的約數 zgsy(); printf("%lld\n",qpow(G,ans,mod+1));//注意mod要+1 return 0; }
\[計算組合數的幾種方法:\\ 1.遞推楊輝三角C_n^m=C_{n-1}^m+C_{n-1}^{m-1}~C[0][0]=C[1][0]=1,求一個組合數可以滾動,倒著列舉,程式碼如下\\ 2.乘法逆元:**這種方法只適用於對答案模一個大質數的情況**,根據通項公式預處理階乘算逆元亂搞\\ 質數一定要大\\ 3.Lucas定理:C_n^m=C_{n/p}^{m/p}*C_{n\%p}^{m\%p}(mod~p)\\ 4.質因數分解,要乘或除的每一個數分解質因數,再把分母的質因數減掉,最後把剩下的質因數乘起來,邊乘邊模p \]
//一維遞推組合數
cin>>n>>m;
m=min(m,n-m);
c[0]=1;
for (int i=1;i<=n;i++)
{
for (int j=m;j>=1;j--)
c[j]=c[j]+c[j-1];
}
cout<<c[m];
//線性推逆元
long long inv[10000005];
inv[1]=1;
long long ny(int x,int p)
{
if (inv[x] != 0) return inv[x];
inv[x]=(p - p / x) * ny(p % x,p) % p;
return inv[x];
}
//費馬小定理求逆元 a mod p乘法逆元=a^(p-2)
快速冪`````
qpow(a,p-2)
//擴歐
void exgcd(LL a, LL b, LL &x, LL &y) //拓展歐幾里得演算法
{
if(!b) x = 1, y = 0;
else
{
exgcd(b, a % b, y, x);
y -= x * (a / b);
}
}
LL niYuan(LL a, LL b) //求a對b取模的逆元
{
LL x, y;
exgcd(a, b, x, y);
return (x + b) % b;
}