exlucas易错点

模板和题解

复习了一下 exlucas的模板,结果写挂四次(都没脸说自己以前写过

是该好好反思一下呢~

错的原因如下:

第一次WA:求阶乘的时候忘了递归处理(n/p)!

第二次WA:求阶乘时把p当成循环节了,循环节应该是(p^k)

第三次WA:把循环节改成(p^k)后,干脆把递归处理(n/p)!改成了递归处理(n/(p^k))! (智障

第四次WA:求(p^k)的逆元直接用(p^k)^(mod-2),然而(p^k)不一定是质数,不能用费马小定理,应该用exgcd求逆元

就因为这几个错误花了我两个小时的时间,其实主要原因是自己没想清楚,连exlucas式子都推错,看题解也太心急了没认真看,导致自己反复错。

还有就是自己数论的基础太差,比如第四次错误就想当然以为(p^k)的逆元是它的(mod-2)次方,连费马小定理的条件都忘了

(PS:好像luogu上此题开O2会全T?相同的代码不开O2都过了)

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 107
 4 #define ll long long
 5 ll p2(ll x,ll mod)
 6 {
 7     return x*x%mod;
 8 }
 9 ll pw(ll x,ll p,ll mod)
10 {
11     return p?p2(pw(x,p/2,mod),mod)*(p&1?x:1)%mod:1;
12 }
13 ll fun(ll n,ll p)
14 {
15     if(n<p)return 0;
16     return fun(n/p,p)+n/p;
17 }
18 ll exfac(ll n,ll p,ll mod)
19 {
20     if(n==0)return 1;
21     ll i,mul=1;
22     for(i=1;i<=mod;i++)
23         if(i%p!=0)mul=mul*i%mod;
24     ll ans=pw(mul,n/mod,mod);
25     ll rest=n%mod;
26     for(i=1;i<=rest;i++)
27         if(i%p!=0)ans=ans*i%mod;
28     return ans*exfac(n/p,p,mod)%mod;
29 }
30 ll exgcd(ll x,ll y,ll &a,ll &b)
31 {
32     ll z;
33     return y?(z=exgcd(y,x%y,b,a),b-=a*(x/y),z):(a=1,b=0,x);
34 }
35 ll getinv(ll a,ll p)
36 {
37     ll x,y;
38     exgcd(a,p,x,y);
39     x=(x%p+p)%p;
40 }
41 ll exlucas(ll n,ll m,ll p,ll mod)
42 {
43     ll ans=exfac(n,p,mod);
44     ans=ans*getinv(exfac(m,p,mod),mod)%mod;
45     ans=ans*getinv(exfac(n-m,p,mod),mod)%mod;
46     ll times=fun(n,p)-fun(m,p)-fun(n-m,p);
47     ans=ans*pw(p,times,mod)%mod;
48     return ans;
49 }
50 ll a[N],b[N],cnt;
51 void getans(ll n,ll m,ll p)
52 {
53     ll t=sqrt(p),i,x=p;
54     for(i=2;i<=p;i++)
55     {
56         if(x%i==0)
57         {
58             ll mod=1;
59             while(x%i==0)x/=i,mod*=i;
60             ll res=exlucas(n,m,i,mod);
61             //printf("%lld\n",res);
62             a[++cnt]=res,b[cnt]=mod;
63         }
64     }
65 }
66 int main()
67 {
68     ll n,m,p,i;
69     scanf("%lld%lld%lld",&n,&m,&p);
70     getans(n,m,p);
71     ll ans=0;
72     for(i=1;i<=cnt;i++)
73     {
74         ll M=p/b[i];
75         ll x=a[i]*M%p*getinv(M,b[i])%p;
76         ans=(ans+x)%p;
77     }
78     printf("%lld\n",ans);
79     return 0;
80 }

 

posted @ 2019-07-14 20:38  lyyi2003  阅读(195)  评论(0编辑  收藏  举报