Alice 正在教她的弟弟 Bob 学数学。
每天,Alice 画一个N行M 列的表格,要求 Bob在格子里填数。
Bob已经学会了自然数1到K的写法。因此他在每个格子里填1 ~ K之间的整数。
Alice 告诉 Bob,如果 Bob 填写完表格的 N*M 个数以后,每行的数从第 1 列到第 M
列单调不减,并且任意两行至少有一列的数不同,而且以前 Bob 没有填写过相同的表格,
那么Alice 就给Bob吃一颗糖果。
Bob想知道,如果每天填写一遍表格,最多能吃到多少颗糖果。
答案模P输出。
第一行,四个整数依次是N, M, K, P。
输出一行,一个整数,表示答案模P 后的结果。
1 3 3 10
0
2 2 2 10
6
样例1:表格只有一行。每个格子可以填写1 ~ 3。有10种填写方法,依次为 1 1 1, 1 1 2, 1 1 3, 1 2 2, 1 2 3, 1 3 3, 2 2 2, 2 2 3, 2 3 3, 3 3 3。
样例2: 表格有两行,有6种填写方法,依次为 1 1/1 2, 1 1/2 2, 1 2/1 1, 1 2/2 2, 2 2/1 1, 2 2/1 2。
1 ≤ N , M ≤ 1 0 5 , 1 ≤ P , K ≤ 2 × 1 0 9 1\leq N,M\leq 10^5,1\leq P,K\leq 2\times 10^9 1≤N,M≤105,1≤P,K≤2×109
每一列单调不减,即为在 k k k个数中选 m m m个数的可重组合数,即 C k + m − 1 k C_{k+m-1}^k Ck+m−1k,令 r = C k + m − 1 k r=C_{k+m-1}^k r=Ck+m−1k。
有 n n n行,每行互不相同,那么总共有 A r n A_r^n Arn种方案,那么答案就是 A r n % p A_r^n\% p Arn%p。
考虑如何求这个数。我们发现 A r n % p = ( A r % p n % p ) % p A_r^n\% p=(A_{r\%p}^{n\% p})\% p Arn%p=(Ar%pn%p)%p,所以我们可以先求 r % p r\%p r%p,即 C k + m − 1 k % p C_{k+m-1}^k\%p Ck+m−1k%p。
假设我们要求 C n m % p C_n^m\% p Cnm%p。设 p = p 1 r 1 p 2 r 2 ⋯ p k r k p=p_1^{r_1}p_2^{r_2}\cdots p_k^{r_k} p=p1r1p2r2⋯pkrk,其中 p i p_i pi为质数。我们可以先求出 C n m % p 1 r 1 , C n m % p 2 r 2 , … , C n m % p k r k C_n^m\%p_1^{r_1},C_n^m\%p_2^{r_2},\dots,C_n^m\%p_k^{r_k} Cnm%p1r1,Cnm%p2r2,…,Cnm%pkrk的值 a 1 , a 2 , … , a k a_1,a_2,\dots,a_k a1,a2,…,ak。
我们把 C n m C_n^m Cnm看作未知数 x x x,可以得到以下方程组:
{ x ≡ a 1 ( m o d p 1 r 1 ) x ≡ a 2 ( m o d p 2 r 2 ) x ≡ a 3 ( m o d p 3 r 3 ) . . . . . . x ≡ a n ( m o d p k r k ) \left\{ \begin{matrix} x\equiv a_1\pmod{p_1^{r_1}}\\ x\equiv a_2\pmod{p_2^{r_2}}\\ x\equiv a_3\pmod{p_3^{r_3}}\\ ......\\ x\equiv a_n\pmod{p_k^{r_k}} \end{matrix} \right. ⎩ ⎨ ⎧x≡a1(modp1r1)x≡a2(modp2r2)x≡a3(modp3r3)......x≡an(modpkrk)
利用中国剩余定理,我们可以求出 x x x,它是以 p p p为周期出现的无穷多个解。而在 [ 0 , p ) [0,p) [0,p)这个周期的解,就是 C n m % p C_n^m\%p Cnm%p后的值。
那么 a 1 , a 2 … , a k a_1,a_2\dots,a_k a1,a2…,ak怎么求呢?
a 1 = C n m % p 1 r 1 = n m ‾ m ! % p 1 r 1 a_1=C_n^m\%p_1^{r_1}=\dfrac{n^{\underline{m}}}{m!}\%p_1^{r_1} a1=Cnm%p1r1=m!nm%p1r1
对于上面这个式子,我们可以将分子和分母的质因子 p 1 p_1 p1个数求出来。因为 C n m C_n^m Cnm是一个整数,所以分子含有的 p 1 p_1 p1的数量一定大于等于分母含有的 p 1 p_1 p1的数量。将分母中的 p 1 p_1 p1约分去掉,此时的分母不含质因数 p 1 p_1 p1,也就是与 p 1 r 1 p_1^{r_1} p1r1互质,那么就可以用欧拉定理求分母的逆元,这样即可求出 a 1 a_1 a1的值。
求出 C k + m − 1 k % p C_{k+m-1}^k\%p Ck+m−1k%p,然后即可求出答案。
#include
using namespace std;
int tot=0,p[105],q[105];
long long n,m,k,mod,ny,jc,vt=1,x,y,now=0,ans=1,a[105],r[105];
long long mi(long long t,long long v){
if(v==0) return 1;
long long re=mi(t,v/2);
re=re*re%mod;
if(v&1) re=re*t%mod;
return re;
}
void exgcd(long long c,long long d){
if(d==0){
x=1;y=0;
return;
}
exgcd(d,c%d);
long long t=x;x=y;y=t-c/d*y;
}
int main()
{
scanf("%lld%lld%lld%lld",&n,&m,&k,&mod);
long long v=mod;
for(int i=2;i*i<=v;i++){
if(v%i==0){
p[++tot]=i;r[tot]=1;
while(v%i==0){
++q[tot];r[tot]*=i;
v/=i;
}
}
}
if(v>1){
p[++tot]=r[tot]=v;q[tot]=1;
}
for(int i=1;i<=tot;i++){
long long v=0;
ny=jc=1;
for(int j=1;j<=m;j++){
long long t=j;
while(t%p[i]==0) t/=p[i],--v;
ny=ny*t%r[i];
t=(m+k-1)-j+1;
while(t%p[i]==0) t/=p[i],++v;
jc=jc*t%r[i];
}
a[i]=mi(ny,r[i]-2)%r[i]*jc%r[i]*(mi(p[i],v)%r[i])%r[i];
vt=vt*r[i];
}
for(int i=1;i<=tot;i++){
exgcd(vt/r[i],r[i]);
x=(x%r[i]+r[i])%r[i];
now=(now+vt/r[i]*a[i]*x%vt)%vt;
}
n%=mod;
for(long long i=now;i>=now-n+1;i--) ans=ans*i%mod;
printf("%lld",ans);
return 0;
}