P2480 [SDOI2010]古代猪文
Lucas定理:(组合数学取模运算)
C n m ≡ C n m o d p m m o d p ∗ C n / p m / p m o d p C_n^m \equiv C_{n\ mod\ p}^{m\ mod\ p}*C_{n/p}^{m/p}\bmod p Cnm≡Cn mod pm mod p∗Cn/pm/pmodp
分析:
-
数论大杂烩:欧拉函数, L u c a s Lucas Lucas定理, C R T CRT CRT
-
由欧拉定理推论,转换一下,题目让求的就是:
q ∑ d ∣ n C n d ≡ q ∑ d ∣ n C n d m o d 999911658 ( m o d 999911659 ) q^{\sum_{d|n}C_{n}^d}\equiv q^{\sum_{d|n}C_{n}^d\ \bmod\ 999911658}(\bmod 999911659) q∑d∣nCnd≡q∑d∣nCnd mod 999911658(mod999911659) -
问题就转换成了求: ∑ d ∣ n C n d m o d 999911658 \sum_{d|n}C_{n}^d\bmod 999911658 ∑d∣nCndmod999911658
质因数分解, 999911658 = 2 ∗ 3 ∗ 4679 ∗ 35617 999911658=2*3*4679*35617 999911658=2∗3∗4679∗35617 ,发现 4 4 4 个质因数指数都是 1 1 1
-
然后枚举 n n n 的约数,运用 L u c a s Lucas Lucas 定理求解组合数,分别计算出 ∑ d ∣ n C n d \sum_{d|n}C_{n}^d ∑d∣nCnd 对 4 4 4 个质因数取模的结果,记为 a 1 , a 2 , a 3 , a 4 a_1,a_2,a_3,a_4 a1,a2,a3,a4
之后再根据 C R T CRT CRT 推回实际的 ∑ d ∣ n C n d m o d 999911658 \sum_{d|n}C_{n}^d\bmod 999911658 ∑d∣nCndmod999911658
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5, mo=999911658;
// 注意mo这里先提前-1,最后算答案的时候还要加回来
int b[5]={0,2,3,4679,35617}, a[5];
// 999911658 质因数分解成 2,3,4679,35617
int fc[N];
void init(int n)
{
fc[0]=1;
for(int i=1;i<=n;i++) fc[i]=fc[i-1]*i%n;
}
int ksm(int a,int b,int p)
{
int ans=1;
while(b)
{
if(b&1) ans=ans*a%p;
b>>=1; a=a*a%p;
}
return ans;
}
int C(int n,int m,int p) // 组合数
{
if(n<m) return 0;
return fc[n]*ksm(fc[m],p-2,p)%p*ksm(fc[n-m],p-2,p)%p;
}
int lucas(int n,int m,int p)
{
if(m>n) return 0;
if(m==0) return 1;
return lucas(n/p,m/p,p)*C(n%p,m%p,p)%p;
}
int crt(int p) // 中国剩余定理,合并回去,返回答案
{
int ans=0;
for(int i=1;i<=4;i++)
{
ans=(ans+a[i]*(p/b[i])%p*ksm(mo/b[i],b[i]-2,b[i]))%p;
}
return ans;
}
signed main()
{
ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int n,q;
cin>>n>>q;
if(q%(mo+1)==0)
{
cout<<"0"<<endl; return 0;
}
for(int i=1;i<=4;i++)
{
init(b[i]);
for(int j=1;j*j<=n;j++)
{
if(n%j==0)
{
a[i]=(a[i]+lucas(n,j,b[i]))%b[i];
int t=n/j;
if(t!=j) a[i]=(a[i]+lucas(n,t,b[i]))%b[i];
}
}
}
int ans=crt(mo);
cout<<ksm(q,ans,mo+1)<<endl;
return 0;
}