快速阶乘算法

快速阶乘算法求:n! mod p\largen!\text{mod}pn! mod p时间复杂度:Θ(nlog⁡n)\Theta(\sqrtn\logn)Θ(n​logn)模板题:P5282【模板】快速阶乘算法参考:P5282【模板】快速阶乘算法(多项式运算+拉格朗日插值+倍增)//minamoto#include<bits/stdc++.h>#defineRregister#definelllonglong#defin

大家好,又见面了,我是你们的朋友全栈君。

求: n !  mod  p \large n! \text{ mod } p n! mod p
时间复杂度: Θ ( n log ⁡ n ) \Theta(\sqrt n \log n) Θ(n
logn)

模板题:P5282 【模板】快速阶乘算法
参考:P5282 【模板】快速阶乘算法(多项式运算+拉格朗日插值+倍增)

//minamoto
#include<bits/stdc++.h>
#define R register
#define ll long long
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;

struct Fast_fac {
	static const int N=(1<<17)+5;int P;
	inline int add(R int x,R int y){return 0ll+x+y>=P?0ll+x+y-P:x+y;}
	inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
	inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
	int ksm(R int x,R int y){
		R int res=1;
		for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
		return res;
	}
	const double Pi=acos(-1.0);
	struct cp{
		double x,y;
		inline cp(){}
		inline cp(R double xx,R double yy):x(xx),y(yy){}
		inline cp operator +(const cp &b)const{return cp(x+b.x,y+b.y);}
		inline cp operator -(const cp &b)const{return cp(x-b.x,y-b.y);}
		inline cp operator *(const cp &b)const{return cp(x*b.x-y*b.y,x*b.y+y*b.x);}
		inline cp operator *(const double &b)const{return cp(x*b,y*b);}
		inline cp operator ~()const{return cp(x,-y);}
	}w[2][N];
	int r[21][N],ifac[N],lg[N],inv[N];double iv[21];
	void Pre(){
		iv[0]=1;
		fp(d,1,17){
			fp(i,0,(1<<d)-1)r[d][i]=(r[d][i>>1]>>1)|((i&1)<<(d-1));
			lg[1<<d]=d,iv[d]=iv[d-1]*0.5;
		}
		inv[0]=inv[1]=ifac[0]=ifac[1]=1;
		fp(i,2,131072)inv[i]=mul(P-P/i,inv[P%i]),ifac[i]=mul(ifac[i-1],inv[i]);
		for(R int i=1,d=0;i<131072;i<<=1,++d)fp(k,0,i-1)
			w[1][i+k]=cp(cos(Pi*k*iv[d]),sin(Pi*k*iv[d])),
			w[0][i+k]=cp(cos(Pi*k*iv[d]),-sin(Pi*k*iv[d]));
	}
	int lim,d;
	void FFT(cp *A,int ty){
		fp(i,0,lim-1)if(i<r[d][i])swap(A[i],A[r[d][i]]);
		cp t;
		for(R int mid=1;mid<lim;mid<<=1)
			for(R int j=0;j<lim;j+=(mid<<1))
				fp(k,0,mid-1)
					A[j+k+mid]=A[j+k]-(t=w[ty][mid+k]*A[j+k+mid]),
					A[j+k]=A[j+k]+t;
		if(!ty)fp(i,0,lim-1)A[i]=A[i]*iv[d];
	}
	void MTT(int *a,int *b,int len,int *c){
	    static cp f[N],g[N],p[N],q[N];
	    lim=len,d=lg[lim];
	    fp(i,0,len-1)f[i]=cp(a[i]>>16,a[i]&65535),g[i]=cp(b[i]>>16,b[i]&65535);
	    fp(i,len,lim-1)f[i]=g[i]=cp(0,0);
	    FFT(f,1),FFT(g,1);
	    fp(i,0,lim-1){
	        cp t,f0,f1,g0,g1;
	        t=~f[i?lim-i:0],f0=(f[i]-t)*cp(0,-0.5),f1=(f[i]+t)*0.5;
	        t=~g[i?lim-i:0],g0=(g[i]-t)*cp(0,-0.5),g1=(g[i]+t)*0.5;
	        p[i]=f1*g1,q[i]=f1*g0+f0*g1+f0*g0*cp(0,1);
	    }
	    FFT(p,0),FFT(q,0);
	    fp(i,0,lim-1)c[i]=((((ll)(p[i].x+0.5)%P<<16)%P<<16)+((ll)(q[i].x+0.5)<<16)+((ll)(q[i].y+0.5)))%P;
	}
	void calc(int *a,int *b,int n,int k){
		static int f[N],g[N],h[N],sum[N],isum[N];
		int len=1;while(len<=n+n)len<<=1;
		fp(i,0,n)f[i]=mul(a[i],mul(ifac[i],ifac[n-i]));
		for(R int i=n-1;i>=0;i-=2)f[i]=P-f[i];
		int t=dec(k,n);
		fp(i,0,n+n)g[i]=add(i,t);
		sum[0]=g[0];fp(i,1,n+n)sum[i]=mul(sum[i-1],g[i]);
		isum[n+n]=ksm(sum[n+n],P-2);
		fd(i,n+n,1)isum[i-1]=mul(isum[i],g[i]);
		fp(i,1,n+n)g[i]=mul(isum[i],sum[i-1]);g[0]=isum[0];
		fp(i,n+1,len-1)f[i]=0;fp(i,n+n+1,len-1)g[i]=0;
		
		MTT(f,g,len,h);
		int res=1,p1=k-n,p2=k;
		fp(i,p1,p2)res=1ll*res*i%P;
		res=dec(res,0);
		
		fp(i,0,n)g[i]=(0ll+P+p1+i)%P;
		sum[0]=g[0];fp(i,1,n)sum[i]=mul(sum[i-1],g[i]);
		isum[n]=ksm(sum[n],P-2);
		fd(i,n,1)isum[i-1]=mul(isum[i],g[i]);
		fp(i,1,n)g[i]=mul(isum[i],sum[i-1]);g[0]=isum[0];
		
		for(R int i=0;i<=n;p2=add(p2,1),++i)
			b[i]=mul(h[i+n],res),res=mul(res,mul(g[i],p2+1));
	}
	int solve(int bl){
		static int a[N],b[N],c[N];
		int s=0;for(int p=bl;p;p>>=1)++s;a[0]=1,--s;
		int qwq=ksm(bl,P-2);
		for(int p=0;s>=0;--s){
			if(p){
				calc(a,b,p,p+1);
				fp(i,0,p)a[p+i+1]=b[i];a[p<<1|1]=0;
				calc(a,b,p<<1,mul(p,qwq));
				p<<=1;fp(i,0,p)a[i]=mul(a[i],b[i]);
			}
			if(bl>>s&1){
				fp(i,0,p)a[i]=mul(a[i],(1ll*bl*i+p+1)%P);
				p|=1,a[p]=1;
				fp(i,1,p)a[p]=mul(a[p],(1ll*bl*p+i)%P);
			}
		}
		int res=1;
		fp(i,0,bl-1)res=mul(res,a[i]);
		return res;
	}
	int GetFac(int n){
		int s=sqrt(n),res=solve(s);
		fp(i,s*s+1,n)res=mul(res,i);
		return res;
	}
	int Fac(int n){
		if(n>P-1-n){
			int res=ksm(GetFac(P-1-n),P-2);
			return (P-1-n)&1?res:P-res;
		}
		return GetFac(n);
	}
} sol;

int main(){
	int n, P, T;
	scanf("%d", &T);
	while(T--) {
		scanf("%d%d", &n, &P);
		sol.P = P, sol.Pre();
		printf("%d\n", sol.Fac(n));
	} 
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/163986.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • JavaScript实现哈希表数据结构[通俗易懂]

    一、简单说明1、JavaScript是没有哈希表数据结构的,那么当我们需要用到类似哈希表这样的键值对数据结构时怎么办?答案就是自己实现一个,我们可以利用JavaScript的一些特性来实现自己的哈希表数据结构。2、首先,哈希表是一种键值对数据结构,键是唯一的,这个特征跟JavaScript的Object对象有点类似,Object对象的属性是唯一的,属性和值的映射就像是键值对一样,那么我们可以用一个…

    2022年4月9日
    60
  • ubuntu中pycharm卸载与安装

    ubuntu中pycharm卸载与安装卸载找到安装包rm-rpycharm-community-2017.3.3#卸载文件夹rm-r.PyCharmCE2017.3#卸载配置文件夹,这一步是很必要的,要不然你的配置被一直记住,相当于没有删除这个在/root里面的隐藏文件安装去官网下载Professional版,拷贝到ubuntu里解压后,进入里面的pycharm-community-2018.1/bin文件夹下执行如下命令安装:./pycharm.sh设置快捷方式:sudogedit/usr/

    2022年8月25日
    6
  • 5个常用的MySQL数据库管理工具_SQL工具

    5个常用的MySQL数据库管理工具_SQL工具原文:http://www.techxue.com/techxue-11898-1.html如今,Web应用程序的响应速度是成功的关键法宝之一。它与用户互动,用户对网站的看法,甚至谷歌网站排名情况都有着密不可分的关系。数据库性能是响应速度最重要的因素之一,一旦出错,所有程序都将会宕机。工欲善其事,必先利其器。几乎每一个Web开发人员都有一个最钟爱的MySQL管理工具,它帮助开发人员在许

    2022年8月22日
    3
  • php 字符串转换时间_php 字符时间如何转换「建议收藏」

    php 字符串转换时间_php 字符时间如何转换「建议收藏」php字符时间转换的方法:1、通过php中的“strtotime()”函数将任何英文文本的日期时间描述解析为时间戳;2、使用php中的“mktime()”函数从日期取得时间戳即可。本文操作环境:windows7系统、PHP5.6版,DELLG3电脑。php字符串转时间戳PHP提供了函数可以方便的将各种形式的日期转换为时间戳,该类函数主要是:strtotime():将任何英文文本的日期时间描述解…

    2022年6月2日
    29
  • tensorflow所有版本_tensorflow最新版本

    tensorflow所有版本_tensorflow最新版本https://pypi.org/project/tensorflow-gpu/1.13.0/#files把13改对你想要的版本

    2022年8月2日
    93
  • Keil5最新注册机到2032

    Keil5最新注册机到2032嘿,好久不见啦,我这个马虎鬼,新的一年大家要平安顺遂、万事如意。真的过了好久没有写博客了,不在的这段时间发生了很多变故,要相信一切都会变美好的。加油啦,马虎鬼~用博客记录点滴,不管怎样,认真做自己吧~一、注册机资源百度i链接:链接:https://pan.baidu.com/s/1chvIeo9UVhnDK-a-Jq3pGg提取码:bi4u二、操作首先用管理员身份打开Keil5;在界面中选中下方菜单栏中的选项;点击后,可以看到如下的界面;选择右上角的ID,选中复制;接着.

    2022年6月14日
    155

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号