写了个 TODO List,如今不会忘写博客了
咕ui
> Link DarkBZOJ 2142spa
\(n\) 件不一样的礼物送给 \(m\) 我的,其中送给第 \(i\) 我的礼物数量为 \(w_i\)。计算出送礼物的方案数(两个方案被认为是不一样的,当且仅当存在某我的在这两种方案中收到的礼物不一样)。因为方案数可能会很大,输出模 \(P\) 后的结果。code
设 \(P=p_1^{c_1}p_2^{c_2}\cdots p_t^{c_t}\),\(p_i\) 为质数,则保证 \(p_i^{c_i}\le10^5\)。递归
普通的 Lucas 定理只能用来求组合数模较小的素数的问题。rem
(部分) Lucas 定理get
$$ \binom{n}{m}\bmod p=\binom{\lfloor\tfrac{n}{p}\rfloor}{\lfloor\tfrac{m}{p}\rfloor}\binom{n\bmod p}{m\bmod p}\bmod p $$ 博客
(可是彷佛不是完整的 Lucas 定理?)string
而 exLucas 定理能够解决 \(p\) 不是一个质数的问题(只要知足「BZOJ 礼物」这道题对 \(p\) 的限制便可)。it
首先对 \(p\) 进行质因数分解 \(p=\prod\limits_{i=1}^tp_i^{c_i}\),设 \(x=\binom{n}{m}\bmod p\),\(x_i=\binom{n}{m}\bmod p_i^{c_i}\),则io
模数互质,能够直接CRT。因此问题转化为「组合数模一个质数的幂 \(p^k\)」。
把组合数的式子展开 \(\binom{n}{m}=\frac{n!}{m!(n-m)!}\),咱们不能直接求 \(m!\) 和 \((n-m)!\) 的逆元,由于它们不必定和 \(p\) 互质。因而想到,能够先把阶乘中 \(p\) 的因子部分提出来,剩下的与 \(p\) 互质的部分就能够求逆元。即
其中 \(p\not\mid b\),\((n-m)!\) 同理。因而剩下的问题就是怎么将阶乘分解成上述形式。
考虑计算 \(a\):统计 \(1,2,\cdots,m\) 中能提取出多少 \(p\) 的因子。比较简单,只须要对每一个 \(p\) 的幂 \(p^i\) 统计 \(1\sim m\) 中有多少 \(p^i\) 的倍数。能够 \(O(\log_p m)\) 完成。
再考虑计算 \(b\),能够递归计算:
能够先预处理出 \(f_i\) 表示 \(1\sim i\) 中全部不为 \(p\) 的倍数的数的积模 \(p^k\),则第一步的答案为
如今就能够快速计算组合数了。
对于这道题,能够直接拆开组合数,计算
而后直接用 exLucas 的拆解阶乘的方法,再用CRT合并(就不须要真的去计算每一个组合数)。
/*Lucky_Glass*/ #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long llong; const int N=100,B=1e5+10; #define con(type) const type & int mul(con(int)a,con(int)b,con(int)mod){return int(1ll*a*b%mod);} int ina_pow(con(int)a,con(llong)b,con(int)mod){return b?mul(ina_pow(mul(a,a,mod),b>>1,mod),(b&1)?a:1,mod):1;} typedef pair<int,llong> pii; int p[N],pc[N],fac[B],phi[N]; llong rem[N],w[N],mod; int n,m,np; void init(){ llong now=mod; for(int i=2;1ll*i*i<=now;i++) if(now%i==0){ p[++np]=i,pc[np]=1; while(now%i==0) now/=i,pc[np]*=i; } if(now>1) np++,p[np]=pc[np]=(int)now; for(int i=1;i<=np;i++) rem[i]=mod/pc[i],phi[i]=pc[i]/p[i]*(p[i]-1); } pii calc(con(llong)x,con(int)p0,con(int)pc0){ if(x<p0) return make_pair(fac[x],0); pii res=calc(x/p0,p0,pc0); return make_pair(mul(mul(res.first,fac[x%pc0],pc0),ina_pow(fac[pc0-1],x/pc0,pc0),pc0),res.second+x/p0); } int func(int p0,int pc0,int phi0){ fac[0]=1; for(int i=1;i<pc0;i++) fac[i]=mul(fac[i-1],i%p0?i:1,pc0); pii up=calc(n,p0,pc0); fac[pc0-1]=ina_pow(fac[pc0-1],phi0-1,pc0); for(int i=pc0-2;i;i--) fac[i]=mul(fac[i+1],(i+1)%p0?i+1:1,pc0); pii blw(1,0); for(int i=1;i<=m;i++){ pii res=calc(w[i],p0,pc0); blw.second+=res.second; blw.first=mul(blw.first,res.first,pc0); } return mul(mul(up.first,blw.first,pc0),ina_pow(p0,up.second-blw.second,pc0),pc0); } int main(){ scanf("%lld%d%d",&mod,&n,&m); init(); llong total=0; for(int i=1;i<=m;i++){ scanf("%lld",&w[i]); total+=w[i]; } if(total>n){printf("Impossible\n");return 0;} if(total<n) w[++m]+=n-total; llong sum=0; for(int i=1;i<=np;i++){ llong now=mul(func(p[i],pc[i],phi[i]),ina_pow(rem[i],phi[i]-1,pc[i]),mod); now=mul(now,rem[i],mod); sum=(sum+now)%mod; } printf("%lld\n",(sum%mod+mod)%mod); return 0; }
史书缺失的那页
遗忘了主角
有人传说这一切
如流光幻夜
——《流光幻夜》By 司夏
> Link 流光幻夜-网易云