1. 程式人生 > >BZOJ.2142.禮物(擴展Lucas)

BZOJ.2142.禮物(擴展Lucas)

oss 禮物 分解 span clu scanf 就是 什麽 while

題目鏈接

答案就是C(n,m1) * C(n-m1,m2) * C(n-m1-m2,m3)...(mod p)
使用擴展Lucas求解。
一個很簡單的優化就是把pi,pi^ki次方存下來,因為每次分解p都是很慢的。
註意最後p不為1要把p再存下來!(質數)

COGS 洛谷上的大神寫得快到飛起啊QAQ 就這樣吧

//836kb 288ms
#include <cmath>
#include <cstdio>
typedef long long LL;

int cnt,P[500],PK[500];
LL FP(LL x,int k,LL p)
{
    LL t=1ll;
    for
(; k; k>>=1,x=x*x%p) if(k&1) t=t*x%p; return t; } LL Exgcd(LL a,LL b,LL &x,LL &y) { if(!b) x=1,y=0; else Exgcd(b,a%b,y,x),y-=a/b*x; } LL Inv(LL a,LL p) { LL x,y; Exgcd(a,p,x,y); return (x%p+p)%p; } LL Fact(LL x,LL pi,LL pk)//Calc x! % (pk=pi^ki)(x!中無pi因子) { if
(!x) return 1ll; LL res=1ll; if(x>=pk) { for(int i=2; i<pk; ++i)//從1開始沒什麽用 if(i%pi) (res*=i)%=pk;//無pi因子! res=FP(res,x/pk,pk); } for(int i=2; i<=x%pk; ++i) if(i%pi) (res*=i)%=pk; return res*Fact(x/pi,pi,pk)%pk; } int C(LL n,LL m,LL pi,LL pk,LL mod)//int
{ if(n<m) return 0; LL a=Fact(n,pi,pk),b=Fact(m,pi,pk),c=Fact(n-m,pi,pk);int k=0; for(LL i=n; i; i/=pi) k+=i/pi; for(LL i=m; i; i/=pi) k-=i/pi; for(LL i=n-m; i; i/=pi) k-=i/pi; LL res=a*Inv(b,pk)%pk*Inv(c,pk)%pk*FP(pi,k,pk)%pk; return res*(mod/pk)%mod*Inv(mod/pk,pk)%mod; } LL Solve(int n,int m,int p) { if(!n) return 1ll; int res=0; for(int i=1; i<=cnt; ++i) (res+=C(n,m,P[i],PK[i],p))%=p; return (LL)res; } int main() { int n,m,p,t[9]; scanf("%d%d%d",&p,&n,&m); int sum=0; for(int i=1; i<=m; ++i) scanf("%d",&t[i]),sum+=t[i]; if(sum>n) {puts("Impossible"); return 0;} int now=p; for(int i=2,lim=sqrt(p+0.5); i<=lim; ++i) if(!(now%i)) { int pk=1; while(!(now%i)) now/=i,pk*=i; P[++cnt]=i, PK[cnt]=pk; if(now==1) break; } if(now!=1) P[++cnt]=now,PK[cnt]=now; LL res=1ll; for(int i=1; i<=m; ++i) (res*=Solve(n,t[i],p))%=p,n-=t[i]; printf("%lld",res); return 0; }

BZOJ.2142.禮物(擴展Lucas)