多项式快速幂

已知 f ( x ) f(x) f(x),求 g ( x ) = f ( x ) k ( m o d x n ) g(x) = f(x)^k\pmod{x^n} g(x)=f(x)k(modxn)

版本 1 : 1: 1:
q k ≤ 1 e 6 qk\leq1e6 qk1e6,其中 q q q f ( x ) f(x) f(x)的最高次数。
f ( x ) f(x) f(x) F F T FFT FFT后直接对每个点值求 k k k次方后再 I D F T IDFT IDFT回去即可。
非常快,不要小看了这种做法。脑筋急转弯
O ( n log ⁡ n ) O(n\log n) O(nlogn)

版本 2 : 2: 2:
k ≤ 1 e 9 k\leq 1e9 k1e9
倍增求快速幂。
注意和上一个版本的区别。
F F T FFT FFT后的操作是一定要注意防止循环卷积出现的,因为这不是我们所希望的。
所以每层都要 I D F T IDFT IDFT然后 ( m o d x n ) \pmod{x^n} (modxn) F F T FFT FFT
(也就是说不要把 ( m o d x n ) \pmod{x^n} (modxn)看做不存在,我们有两个模数,一个是 x n x^n xn,一个是 998244353 998244353 998244353
O ( n log ⁡ n log ⁡ k ) O(n\log n\log k) O(nlognlogk)

版本 3 : 3: 3:
k ≤ 1 e 1 e 50 k\leq 1e1e50 k1e1e50,保证 f ( x ) [ 0 ] = 1 f(x)[0]=1 f(x)[0]=1对你没有看错
我们考虑 f ( x ) k = exp ⁡ ( k ln ⁡ f ( x ) ) f(x)^k=\exp(k\ln f(x)) f(x)k=exp(klnf(x))
发现在 ( m o d 998244353 ) \pmod {998244353} (mod998244353)的意义下.
k ln ⁡ f ( x ) ≡ ( k m o d    998244353 ) f ( x ) ( m o d 998244353 ) k\ln f(x) \equiv (k\mod 998244353) f(x) \pmod {998244353} klnf(x)(kmod998244353)f(x)(mod998244353)
所以我们可以在读入时把 k m o d    998244353 k\mod 998244353 kmod998244353
然后我们既可以用 exp ⁡ \exp exp
也可以用版本 2 2 2的方法。
注意因为我们要求 ln ⁡ f ( x ) [ 0 ] ( m o d 998244353 ) \ln f(x)[0] \pmod {998244353} lnf(x)[0](mod998244353)
所以我们需要 f ( x ) [ 0 ] = 1 , ln ⁡ f ( x ) [ 0 ] = 0 f(x)[0]=1 , \ln f(x)[0] = 0 f(x)[0]=1,lnf(x)[0]=0
不然,我实在不知道自然对数模一个素数的值是多少。

版本 4 : 4: 4
k ≤ 1 e 1 e 50 k\leq 1e1e50 k1e1e50,不保证 f ( x ) [ 0 ] = 1 f(x)[0]=1 f(x)[0]=1
考虑我们求 exp ⁡ \exp exp的过程,是用牛顿迭代。
那么我们需要一个初值 x x x
这个初值应该满足 x = exp ⁡ k ln ⁡ f ( x ) [ 0 ] = f ( x ) [ 0 ] k x = \exp{k\ln f(x)[0]} = f(x)[0]^k x=expklnf(x)[0]=f(x)[0]k
所以我们只需要在求 exp ⁡ \exp exp的时候将初值设定为这个即可。
不用管 ln ⁡ \ln ln后的第 0 0 0项是多少,它再 exp ⁡ \exp exp后的第 0 0 0项就是这个值。
但是 ln ⁡ 0 \ln 0 ln0是没有定义的,
所以 f ( x ) [ 0 ] = 0 f(x)[0]=0 f(x)[0]=0时我们需要平移多项式。

挂个大佬的链接

A C   C o d e \mathrm {AC \ Code} AC Code

#include<bits/stdc++.h>
#define maxn 300005
#define rep(i,j,k) for(int i=(j);i<=(k);i++)
#define per(i,j,k) for(int i=(j);i>=(k);i--)
#define mod 998244353
using namespace std;

int Wl,W[maxn],lg[maxn],r[maxn],inv[maxn];
int Pow(int b,int k){ int r=1;for(;k;k>>=1,b=1ll*b*b%mod) if(k&1) r=1ll*r*b%mod;return r; }
struct cp{int a,b;cp(int a=0,int b=0):a(a),b(b){}};
cp mul(cp a,cp b,int w){ return cp((1ll*a.a*b.a+1ll*w*a.b%mod*b.b)%mod,(1ll*a.a*b.b+1ll*a.b*b.a)%mod); }
cp Pow(cp b,int k,int w){ cp r(1,0);for(;k;k>>=1,b=mul(b,b,w)) if(k&1) r=mul(r,b,w);return r; }
int SQRT(int n){
	if(Pow(n,(mod-1)/2)==mod-1) return -1;
	for(int a,w;a=rand(),1;) if(Pow((w=(1ll*a*a-n)%mod+mod)%mod,(mod-1)/2)==mod-1) 
		return Pow(cp(a,1),(mod+1)/2,w).a;
}
void init(int n){
	for(W[0]=inv[0]=inv[1]=Wl=1;n>=2*Wl;Wl<<=1);int pw=Pow(3,(mod-1)/Wl/2);
	rep(i,1,Wl<<1) W[i]=1ll*W[i-1]*pw%mod,(i>1)&&(lg[i]=lg[i>>1]+1,inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod);
}
void FFT(int *A,int n,int tp){
	rep(i,1,n-1) (i<(r[i]=(r[i>>1]>>1)|((i&1)<<(lg[n]-1))))&&(swap(A[i],A[r[i]]),0);
	for(int L=1,B=Wl;L<n;L<<=1,B>>=1) for(int s=0;s<n;s+=L<<1) for(int k=s,x=0,t;k<s+L;k++,x+=B) 
		t=1ll*(tp==1?W[x]:W[(Wl<<1)-x])*A[k+L]%mod,A[k+L]=(A[k]-t)%mod,A[k]=(A[k]+t)%mod;
	if(tp^1) rep(i,0,n-1) A[i]=1ll*A[i]*inv[n]%mod;
}
void INV(int *A,int *B,int n){
	B[B[1]=0]=Pow(A[0],mod-2);static int t[maxn];
	for(int k=2,L=4;k<(n<<1);k<<=1,L<<=1){
		rep(i,0,L-1) t[i]=i<k?A[i]:B[i]=0;FFT(t,L,1),FFT(B,L,1);
		rep(i,0,L-1) B[i]=B[i]*(2-1ll*t[i]*B[i]%mod)%mod;FFT(B,L,-1);
		rep(i,min(n,k),L-1) B[i]=0;
	}
}
void LN(int *A,int *B,int n){
	INV(A,B,n);static int t[maxn];int L=1<<lg[2*n-2]+1;
	rep(i,0,L-1) t[i]=i<n-1?A[i+1]*(i+1ll)%mod:0,(i>=n)&&(B[i]=0);FFT(B,L,1),FFT(t,L,1);
	rep(i,0,L-1) t[i]=1ll*t[i]*B[i]%mod;FFT(t,L,-1);
	rep(i,0,L-1) B[i]=(i&&i<n?1ll*t[i-1]*inv[i]%mod:0);
}
void EXP(int *A,int *B,int n,int b0=1){
	B[B[1]=0]=b0;static int t[maxn];
	for(int k=2,L=4;k<(n<<1);k<<=1,L<<=1){
		LN(B,t,k);rep(i,0,L-1) t[i]=i<k?((i==0)-t[i]+A[i])%mod:B[i]=0;
		FFT(t,L,1),FFT(B,L,1);rep(i,0,L-1) B[i]=1ll*B[i]*t[i]%mod;
		FFT(B,L,-1);rep(i,min(n,k),L-1) B[i]=0;
 	}
}
void SQT(int *A,int *B,int n){
	B[0]=SQRT(A[0]);if(B[0]>mod-B[0]) B[0] = mod-B[0];
	B[1]=0;static int t[maxn],t2[maxn];
	for(int k=2,L=4;k<(n<<1);k<<=1,L<<=1){
		INV(B,t,k);rep(i,0,L-1) t2[i]=i<k?A[i]:t[i]=0;
		FFT(t,L,1),FFT(t2,L,1);rep(i,0,L-1) t[i]=1ll*t[i]*t2[i]%mod;
		FFT(t,L,-1);rep(i,0,L-1) B[i]=(i<min(k,n)?(B[i]+t[i])*(mod+1ll)/2%mod:0); 
	}
}
void INT(int *A,int *B,int n){ rep(i,0,n-1) B[i] = (i ? 1ll * A[i-1] * inv[i] % mod : 0);}
void DER(int *A,int *B,int n){ rep(i,0,n-2) B[i]=A[i+1]*(i+1ll)%mod; }
void POW(int *A,int *B,int n,int k){ 
	static int t[maxn],t2[maxn];
	int p=0;for(;p<n && A[p]==0;p++);
	if(1ll*p*k>=n-1){
		rep(i,0,n-1) B[i]=0;
		return;
	}
	rep(i,p,n) t2[i-p]=A[i];
	LN(t2,t,n-p*k);
	rep(i,0,n-p*k-1) t[i]=1ll*t[i]*k%mod;
	EXP(t,B,n-p*k,Pow(t2[0],k));
	per(i,n-1,0) B[i]=i<p*k?0:B[i-p*k];
}
int n,m,k;int A[maxn],B[maxn];
int main(){
	scanf("%d",&n);init(2*n);
	char ch;
	for(;!isdigit(ch=getchar()););
	for(k=ch-'0';isdigit(ch=getchar());k=(k*10ll+ch-'0')%mod);
	rep(i,0,n-1) scanf("%d",&A[i]);
	POW(A,B,n,k);
	rep(i,0,n-1) printf("%d%c",(B[i]+mod)%mod," \n"[i==n-1]);
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值