luogu 4720 【模板】扩展卢卡斯

题目大意:

求$C_n^m \mod p$,p不一定为质数

思路:

首先可以将$p$分解为$p1^{a1}*p2^{a2}*...*pk^{ak}$,对于这些部分可以使用$CRT$合并

对于每个$p_i^{k_i}$,阶乘是存在循环的例如$19!$与模数$9$

$1*2*4*5*7*8$与$10*11*13*14*16*17$对答案的贡献一样,因此可以快速幂

对于剩下的部分因为很少可以暴力

对于求阶乘的部分 用这种方法求出循环节和剩余部分然后继续递归即可

求$C$的时候$C_n^m \mod p^k= \frac{n! / p^a}{m! / p^b \times (n-m)! / p^c} * p^{a-b-c} \mod p^k$

然后就是$CRT$套上述这一堆东西

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<cmath>
 6 #include<algorithm>
 7 #include<queue>
 8 #include<vector>
 9 #include<map>
10 #include<set>
11 #define ll long long
12 #define db double
13 #define inf 2139062143
14 #define MAXN 200100
15 #define rep(i,s,t) for(register int i=(s),i##__end=(t);i<=i##__end;++i)
16 #define dwn(i,s,t) for(register int i=(s),i##__end=(t);i>=i##__end;--i)
17 #define ren for(register int i=fst[x];i;i=nxt[i])
18 #define pb(i,x) vec[i].push_back(x)
19 #define pls(a,b) (a+b)%MOD
20 #define mns(a,b) (a-b+MOD)%MOD
21 #define mul(a,b) (1LL*(a)*(b))%MOD
22 using namespace std;
23 inline ll read()
24 {
25     ll x=0,f=1;char ch=getchar();
26     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
27     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
28     return x*f;
29 }
30 ll T,n,m,MOD;
31 ll q_pow(ll a,ll t,ll p,ll res=1)
32 {
33     for(a%=p;t;t>>=1,(a*=a)%=p)
34         if(t&1) (res*=a)%=p;return res;
35 }
36 ll exgcd(ll a,ll b,ll &x,ll &y)
37 {
38     if(!b){x=1,y=0;return a;}
39     ll d=exgcd(b,a%b,y,x);y-=(a/b)*x;return d;
40 }
41 ll pw(ll n,ll p,ll pk)
42 {
43     if(!n) return 1;ll res=1;
44     rep(i,2,pk) if(i%p) (res*=i)%=pk;
45     res=q_pow(res,n/pk,pk);
46     rep(i,2,n%pk) if(i%p) (res*=i)%=pk;
47     return (res*pw(n/p,p,pk))%pk;
48 }
49 ll inv(ll n,ll p) {ll x,y;exgcd(n,p,x,y);return (x+p)%p;}
50 ll C(ll n,ll m,ll p,ll pk)
51 {
52     ll pn=pw(n,p,pk),pm=pw(m,p,pk),pz=pw(n-m,p,pk),sum=0;
53     for(ll i=n;i;i/=p) sum+=i/p;for(ll i=m;i;i/=p) sum-=i/p;
54     for(ll i=n-m;i;i/=p) sum-=i/p;
55     pm=inv(pm,pk),pz=inv(pz,pk);
56     return (((q_pow(p,sum,pk)*pn)%MOD*pm)%MOD*pz)%MOD;
57 }
58 void exlucas(ll n,ll m)
59 {
60     ll p=MOD,rs=p,k,ans=0,x,y;
61     rep(i,2,sqrt(MOD))
62     {
63         k=1;while(rs%i==0) rs/=i,k*=i;
64         if(k!=1) (ans+=(inv(p/k,k)*p/k)%MOD*C(n,m,i,k)+MOD)%=MOD;
65     }
66     if(rs!=1) (ans+=(inv(p/rs,rs)*p/rs)%MOD*C(n,m,rs,rs)+MOD)%=MOD;
67     printf("%lld\n",ans);
68 }
69 int main()
70 {
71     n=read(),m=read(),MOD=read();exlucas(n,m);
72 }
View Code

 

posted @ 2019-03-14 12:31  jack_yyc  阅读(139)  评论(0编辑  收藏  举报