扩展lucas学习笔记

版权声明:蒟蒻写的..能不能吱一声呀 https://blog.csdn.net/Rose_max/article/details/83869283

胡思乱想

最后的沉沦??

用处

C n m m o d p C_n^m mod p 的结果,不保证 p p 为质数

水法

p p 分解质因数,可以知道
p = p 1 k 1 p 2 k 2 . . . p n k n p=p1^{k1}*p2^{k2}*...*pn^{kn}
如果我们能知道
a n s a 1 ( m o d    p 1 k 1 ) ans\equiv a1(\mod p1^{k1})
a n s a 2 ( m o d    p 2 k 2 ) ans\equiv a2(\mod p2^{k2})
a n s a n ( m o d    p n k n ) ans\equiv an(\mod pn^{kn})
就可以同余方程组合并了
于是现在你要求的就是 C n m m o d p k C_n^mmodp^k
如果我们能知道 n ! m o d p k n!modp^k m ! m o d p k m!modp^k ( n m ) ! m o d p k (n-m)!modp^k
显然能通过逆元得到答案
举例一个 n = 19 , p i = 3 , k = 2 n=19,pi=3,k=2
可以把他分组得到
( 1 2 3 4 5 . . . 19 ) (1*2*3*4*5*...*19)
= ( 1 2 4 5 7 8 10 11 13 14 16 17 19 ) 3 6 ( 1 2 3 4 5 6 ) =(1*2*4*5*7*8*10*11*13*14*16*17*19)*3^6*(1*2*3*4*5*6)
前面不包含pi的因子
后面又是一个阶乘可以递归计算
第一部分发现他们关于 p k p^k 分组同余
最后剩下一部分暴力算
复杂度上界是 p k p^k
然后就到最后求逆元的时候了
发现其实他们是不互质的,因为存在因子 p i pi
把三个阶乘中因子 p i pi 全部去掉,因为是除法可以直接减掉最后再乘
然后求逆元即可

板子

bzoj2142

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#define LL long long
#define mp(x,y) make_pair(x,y)
using namespace std;
inline int read()
{
	int f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline void write(int x)
{
	if(!x){putchar('0');return ;}
	static int sta[20],top=0;
	while(x)sta[++top]=x%10,x/=10;
	while(top)putchar(sta[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(int x){write(x);putchar('\n');}
LL pow_mod(LL a,LL b,LL mod)
{
	LL ret=1;
	while(b)
	{
		if(b&1)ret=ret*a%mod;
		a=a*a%mod;b>>=1;
	}
	return ret;
}
LL exgcd(LL a,LL b,LL &x,LL &y)
{
	if(a==0)
	{
		x=0;y=1;
		return b;
	}
	else
	{
		LL tx,ty;
		LL d=exgcd(b%a,a,tx,ty);
		x=ty-(b/a)*tx;
		y=tx;
		return d;
	}
}
LL inv(LL A,LL mod)
{
	LL x,y,K=1;
	LL d=exgcd(A,mod,x,y);
	x=(x*(K/d)%(mod/d)+(mod/d))%(mod/d);
	return x;
}
LL solve(LL n,LL pi,LL mod)//非互质  mod=pi^k 
{
	if(!n)return 1;
	LL ret=1;
	for(int i=2;i<=mod;i++)if(i%pi)ret=ret*i%mod;
	ret=pow_mod(ret,n/mod,mod);
	for(int i=2;i<=n%mod;i++)if(i%pi)ret=ret*i%mod;
	return ret*solve(n/pi,pi,mod)%mod;//递归计算另外一个阶乘pi^u*(1*2*3...) 
}
LL exlucas(LL n,LL m,LL pi,LL mod)
{
	if(m>n)return 0;
	LL a=solve(n,pi,mod),b=solve(m,pi,mod),c=solve(n-m,pi,mod);
	LL 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;
	return a*inv(b,mod)%mod*inv(c,mod)%mod*pow_mod(pi,k,mod)%mod;
}
LL a1[100005],p1[100005],p2[100005],ln,P,n,m,temp;
LL query()
{
	if(ln==1)return a1[1];
	LL m1=p1[1],b1=a1[1],m2,b2;
	for(int i=2;i<=ln;i++)
	{
		m2=p1[i];b2=a1[i];
		LL A=m1,B=m2,K=b2-b1,x,y;
		LL d=exgcd(A,B,x,y);
		x=(x*(K/d)%(B/d)+(B/d))%(B/d);
		b1=m1*x+b1;m1=m1/d*m2;
	}
	return b1;
}
LL work(LL n,LL m)
{
	for(int i=1;i<=ln;i++)a1[i]=exlucas(n,m,p2[i],p1[i]);
	return query()%temp;
}
int sum,w[10];
int main()
{
	P=read();temp=P;
	n=read();m=read();
	for(int i=1;i<=m;i++)w[i]=read(),sum+=w[i];
	if(sum>n)return puts("Impossible\n"),0;
	for(int i=2;i*i<=P;i++)if(!(P%i))
	{
		ln++;p2[ln]=i;p1[ln]=1;
		while(!(P%i))p1[ln]*=i,P/=i;
	}
	if(P!=1)ln++,p1[ln]=p2[ln]=P;
	LL ans=work(n,n-sum);
	for(int i=1;i<=m;i++)
	{
		ans=ans*work(sum,w[i])%temp;
		sum-=w[i];
	}
	pr2(ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Rose_max/article/details/83869283