bzoj 2142 国家集训队试题 礼物
问题转化成求C(N,M) mod P p为非素数,那么我们可以将P分解质因数,
也就是 π pi^ci的形式,因为这些pi^ci是互质的,所以我们可以用crt将他们合并
那么问题就转化成了快速求C(N,M) mod pi^ci
那么我们看下c的形式,为N!/(M!(N-M)!) mod pi^ci
因为mod的数不是质数,所以分母没法正常求逆元,那么我们可以将分子分母
中的pi的值挑出,那么我们先求N!,可以发现,N!mod pi^ci可以分段,每段是
pi^ci长,这一段的值是0--(pi^ci-1),那么因为我们需要将N!中pi|I的挑出来
剩下一些数,那就是好几段这个数相乘,用快速幂解决就行了,设cnt为p!其中
不包括pi|n的
那么N! mod pi^ci就变成了cnt^x*pi^y,那么x,y我们可以求出来,然后div掉p
之后,就又出现了一个阶乘,那么递归去做就行了。
比如N=11 pi=2 ci=2
N!为1*2*3*4*5*6*7*8*9*10*11
那么就是[1*3]*[5*7]*[9*11] mod pi^ci
挑出来的数是2,4,6,8,10,都div pi之后是
1,2,3,4,5 然后就成一个子问题了。
/************************************************************** Problem: 2142 User: BLADEVIL Language: Pascal Result: Accepted Time:492 ms Memory:228 kb ****************************************************************/ //By BLADEVIL var m, n :longint; pj, c :array[0..110] of longint; pi, s, a :array[0..110] of int64; p :int64; tot :longint; procedure divide(p:int64); var i, j :longint; begin tot:=0; for i:=2 to trunc(sqrt(p)) do if p mod i=0 then begin inc(tot); pj[tot]:=i; while p mod i=0 do begin inc(c[tot]); p:=p div i; end; end; if p>1 then begin inc(tot); pj[tot]:=p; c[tot]:=1; end; for i:=1 to tot do begin pi[i]:=1; for j:=1 to c[i] do pi[i]:=pi[i]*pj[i]; end; end; function ex_gcd(a,b:int64;var x,y:int64):int64; var t :int64; begin if (b=0) then begin x:=1;y:=0; exit(a); end; ex_gcd:=ex_gcd(b,a mod b,x,y); t:=x; x:=y; y:=t-(a div b)*y; end; function gcd(a,p:int64):int64; var x, y :int64; begin x:=0;y:=0; ex_gcd(a,p,x,y); x:=(x mod p+p)mod p; exit(x); end; function mi(x,y,q:int64):int64; var rec :int64; begin rec:=1; while (y>0) do begin if y and 1=1 then rec:=rec*x mod q; x:=x*x mod q; y:=y shr 1; end; exit(rec); end; function fac(n,p,q:int64):int64; var cnt :int64; i :longint; begin cnt:=1; for i:=1 to n do if (i mod p>0) then cnt:=cnt*i mod q; exit(cnt); end; function fact(n:int64;var sum:int64;p,q:int64):int64; var cnt, rec :int64; begin rec:=1; cnt:=fac(q,p,q); while n>=p do begin sum:=sum+n div p; if (n div q>0) then rec:=rec*(mi(cnt,n div q,q) mod q)mod q; if (n mod q>0) then rec:=rec*(fac(n mod q,p,q)mod q) mod q; n:=n div p; end; if n>1 then rec:=rec*fac(n,p,q) mod q; exit(rec); end; function combine(n,m,p,q:int64):int64; var ans1, ans2, ans3, ans :int64; a, b, c :int64; begin a:=0;b:=0;c:=0; ans1:=fact(n,a,p,q); ans2:=fact(m,b,p,q); ans3:=fact(n-m,c,p,q); a:=a-(b+c); ans:=mi(p,a,q); ans:=ans*ans1 mod q; ans:=ans*gcd(ans2,q) mod q; ans:=ans*gcd(ans3,q) mod q; exit(ans); end; function doit(n,m:longint):int64; var i :longint; x, y, sum :int64; begin sum:=0; for i:=1 to tot do a[i]:=combine(n,m,pj[i],pi[i]); for i:=1 to tot do begin x:=0;y:=0; ex_gcd(s[i],pi[i],x,y); x:=(x mod pi[i]+pi[i])mod pi[i]; sum:=(sum+((x*s[i] mod p)*a[i])mod p)mod p; end; exit(sum mod p); end; procedure main; var i :longint; w :array[0..100] of longint; ans :int64; sum :int64; begin readln(p); divide(p); for i:=1 to tot do s[i]:=p div pi[i]; readln(n,m); sum:=0; for i:=1 to m do begin readln(w[i]); inc(sum,w[i]); end; if sum>n then begin writeln('Impossible'); exit; end; ans:=1; for i:=1 to m do begin ans:=ans*doit(n,w[i]) mod p; n:=n-w[i]; end; writeln(ans); end; begin main; end.