zoukankan      html  css  js  c++  java
  • 【模板】多项式快速幂

    VI.【模板】多项式快速幂

    我们要求\(g=f^k\)

    两边求\(\ln\)得到

    \[\ln g=k\ln f \]

    然后再幂回去

    \[g=e^{k\ln f} \]

    于是一次\(\ln\),一次\(\exp\)即可解决。

    关于那个超大的\(k\),在读入的时候直接\(\bmod\)上去即可。

    时间复杂度\(O(n\log n)\)

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1<<20;
    const int mod=998244353;
    const int G=3;
    int n,m,rev[N],f[N],g[N],all;
    int ksm(int x,int y){
    	int rt=1;
    	for(;y;x=(1ll*x*x)%mod,y>>=1)if(y&1)rt=(1ll*rt*x)%mod;
    	return rt;
    }
    void NTT(int *a,int tp,int LG){
    	int lim=(1<<LG),invlim=ksm(lim,mod-2);
    	for(int i=0;i<lim;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(LG-1));
    	for(int i=0;i<lim;i++)if(i<rev[i])swap(a[i],a[rev[i]]);
    	for(int md=1;md<lim;md<<=1){
    		int rt=ksm(G,(mod-1)/(md<<1));
    		if(tp==-1)rt=ksm(rt,mod-2);
    		for(int stp=md<<1,pos=0;pos<lim;pos+=stp){
    			int w=1;
    			for(int i=0;i<md;i++,w=(1ll*w*rt)%mod){
    				int x=a[pos+i],y=(1ll*w*a[pos+md+i])%mod;
    				a[pos+i]=(x+y)%mod;
    				a[pos+md+i]=(x-y+mod)%mod;
    			}
    		}
    	}
    	if(tp==-1)for(int i=0;i<lim;i++)a[i]=(1ll*a[i]*invlim)%mod;
    }
    int A[N],B[N],C[N],D[N];
    void mul(int *a,int *b,int *c,int LG){//get a*b multiplied together in array c.(can be the same array)
    	int lim=(1<<LG);
    	for(int i=0;i<lim;i++)A[i]=B[i]=0;
    	for(int i=0;i<(lim>>1);i++)A[i]=a[i],B[i]=b[i];
    	NTT(A,1,LG),NTT(B,1,LG);
    	for(int i=0;i<lim;i++)A[i]=1ll*A[i]*B[i]%mod;
    	NTT(A,-1,LG);
    	for(int i=0;i<lim;i++)c[i]=A[i];
    }
    void inv(int *a,int *b,int LG){//get a^{-1} in array b(CAN'T BE THE SAME ARRAY)
    	b[0]=ksm(a[0],mod-2);
    	for(int k=1;k<=LG+1;k++){
    		mul(b,a,C,k);
    		for(int i=0;i<(1<<k);i++)C[i]=(mod-C[i])%mod;
    		(C[0]+=2)%=mod;
    		mul(C,b,b,k);
    	}
    }
    void diff(int *a,int *b,int lim){//get the diffentiated array of a in array b(can be the same array)
    	for(int i=0;i<lim;i++)b[i]=1ll*a[i+1]*(i+1)%mod;
    	b[lim-1]=0;
    }
    void inte(int *a,int *b,int lim){//get the intergrated array of a in array b(can be the same array)
    	for(int i=lim-1;i;i--)b[i]=1ll*a[i-1]*ksm(i,mod-2)%mod;
    	b[0]=0;
    }
    void ln(int *a,int *b,int LG){//get ln(a) in array b(CAN'T BE THE SAME ARRAY)
    	inv(a,b,LG);
    	diff(a,C,1<<LG);
    	mul(b,C,b,LG+1);
    	inte(b,b,1<<LG);
    }
    void exp(int *a,int *b,int LG){//get e^a in array b(CAN'T BE THE SAME ARRAY)
    	b[0]=1;
    	for(int k=1;k<=LG+1;k++){
    		ln(b,D,k-1);
    		for(int i=0;i<(1<<(k-1));i++)D[i]=(a[i]-D[i]+mod)%mod;
    		D[0]=(D[0]+1)%mod;
    //		for(int i=0;i<(1<<(k-1));i++)printf("%d ",D[i]);puts("");
    		mul(b,D,b,k);
    	}
    }
    void ksm(int *a,int k,int *b,int LG){//get a^k in array b(CAN'T BE THE SAME ARRAY)
    	ln(a,b,LG);
    	for(int i=0;i<(1<<LG);i++)a[i]=1ll*b[i]*k%mod;
    	exp(a,b,LG);
    }
    void getm(){
    	m=0;
    	char ch=getchar();
    	while(ch>'9'||ch<'0')ch=getchar();
    	while(ch>='0'&&ch<='9')m=(10ll*m+ch-'0')%mod,ch=getchar();
    } 
    int main(){
    	scanf("%d",&n),getm();
    	for(int i=0;i<n;i++)scanf("%d",&f[i]);
    	while((1<<all)<n)all++;
    	ksm(f,m,g,all);
    	for(int i=0;i<n;i++)printf("%d ",g[i]);puts("");
    	return 0;
    }
    

  • 相关阅读:
    LeetCode 230. 二叉搜索树中第K小的元素(Kth Smallest Element in a BST)
    LeetCode 216. 组合总和 III(Combination Sum III)
    LeetCode 179. 最大数(Largest Number)
    LeetCode 199. 二叉树的右视图(Binary Tree Right Side View)
    LeetCode 114. 二叉树展开为链表(Flatten Binary Tree to Linked List)
    LeetCode 106. 从中序与后序遍历序列构造二叉树(Construct Binary Tree from Inorder and Postorder Traversal)
    指针变量、普通变量、内存和地址的全面对比
    MiZ702学习笔记8——让MiZ702变身PC的方法
    你可能不知道的,定义,声明,初始化
    原创zynq文章整理(MiZ702教程+例程)
  • 原文地址:https://www.cnblogs.com/Troverld/p/14607853.html
Copyright © 2011-2022 走看看