「狗屁不会」exlucas

填坑
考试的时候不会自闭了,考完板子打不对自闭了。
lucas用来处理一类问题 \(C_n^{m}mod\ P\) 其中P为质数。
可是如果P变成GK非质数了咋办??
就要用exlucas了。
首先,如果设P=\(\prod {p_i}^{c_i}\),那么如果能分别求出组合数模质数幂的答案,就可以用CRT合并了。
现在问题转化为求\(C_n^m mod\ p^k\)
有基本式子\(C_n^m=\frac{n!}{m!(n-m)!}\),然后唯一的问题就是如果n!,(n-m)!模\(p^k\)意义下无逆元怎么办。
无逆元是因为不互质,所以考虑把p都提出来,也就是\(C_n^m=\frac{\frac{n!}{p^x}}{\frac{m!}{p^y}\frac{(n-m)!}{p^z}}p^{x-y-z}\)也就是求参考lucas的形式,可以递归实现求\(\frac{n!}{p^x}\)
具体来说,对于n先把含p因子的提出来。
\(n!=p^{\left \lfloor \frac{n}{p} \right \rfloor}\left \lfloor \frac{n}{p} \right \rfloor!\prod\limits_{i=1\&\&i\perp p}^n i\)
质因子只会来自于第一项与第二项。第一项直接搞掉,第二项递归下去,第三项可以预处理。
具体看代码吧。

#include<cstdio>
#include<iostream>
#define LL long long
#define int LL
#define Pair pair<int,int>
#define fr first
#define sc second
#define mp make_pair
using namespace std;
const int N=35;
int pk[N],pc[N],tt,p,k,kx,tk[N],js[N][1000005];
inline int qpow(int a,int b,int mod=k,int c=1) {
	for(;b;b>>=1,a=1ll*a*a%mod) if(b&1) c=1ll*c*a%mod;
	return c;
}
Pair calc(int x) {
	if(!x) return make_pair(1,0);Pair tmp=calc(x/p);
	return make_pair(tmp.fr*qpow(js[kx][k-1],x/k)%k*js[kx][x%k]%k,tmp.sc+x/p);
}
inline int C(int n,int m) {
	if(m>n) return 0; Pair x=calc(n),y=calc(m),z=calc(n-m);
	return x.fr*qpow(y.fr,k-k/p-1)%k*qpow(z.fr,k-k/p-1)%k*qpow(p,x.sc-y.sc-z.sc)%k;
}
inline int CRT(int ans=0,int M=1) {
	for(int i=1;i<=tt;++i) M=M*pc[i];
	for(int i=1;i<=tt;++i) k=pc[i],ans=(ans+qpow(M/k,pc[i]-pc[i]/pk[i]-1)*tk[i]%k*(M/k))%M;
	return ans;
}
signed main() {
	LL n,m;int P; scanf("%lld%lld%lld",&n,&m,&P);int x=P;
	for(int i=2;i*i<=x;++i) {
		if(x%i==0) {
			++tt;pk[tt]=pc[tt]=i;x/=i;
			while(x%i==0) x/=i,pc[tt]*=i;
		}
	}
	if(x^1) ++tt,pk[tt]=pc[tt]=x;
	for(kx=1;kx<=tt;++kx) {
		js[kx][0]=1;p=pk[kx],k=pc[kx];
		for(int j=1;j<k;++j) {
			if(j%p==0) js[kx][j]=js[kx][j-1];
			else js[kx][j]=1ll*js[kx][j-1]*j%k;
		}
		tk[kx]=C(n,m);
	}
	printf("%lld\n",CRT());
	return 0;
}
posted on 2020-01-02 21:10  _kx  阅读(287)  评论(2编辑  收藏  举报