多项式重探

Part1:牛顿迭代

我们有形式幂级数f,t.复合t(f)=0

f_{0}\equiv f\ (mod\ x^n)

将t(f)在f0处泰勒展开

t(f)=\frac{t(f_{0})}{0!}+\frac{t'(f_{0})}{1!}(f-f_{0})+\frac{t''(f_{0})}{2!}(f-f_{0})^2....

然后我们考虑在膜x^{2n}下的意义

\\t(f_{0})+t'(f_{0})(f-f_{0})\equiv 0\ (mod\ x^{2n})\\ \\ f\equiv f_{0}-\frac{t(f_{0})}{t'(f_{0})}\ (mod\ x^{2n})

 

Part2:求逆

已知f,求g\equiv f^{-1}\ (mod\ x^n)

我们构造t(g)=fg-1,那么我们有

\\g\equiv g_{0}-\frac{g_{0}f-1}{f}\ (mod\ x^{2n})\\ \\ g\equiv g_{0}-(g_{0}f-1)g_{0}\ (mod\ x^{2n})\\ \\ g\equiv 2g_{0}-g_{0}^2f\ (mod\ x^{2n})

 

Part3:ln

已知f,求g\equiv ln(f)\ (mod\ x^n)

我们对两边求导

g'\equiv f^{-1}f'\ (mod\ x^{n})

 

Part4:exp

已知f,求g\equiv e^{f}\ (mod\ x^n)

我们构造t(g)=ln(g)-f

\\g\equiv g_{0}-\frac{ln(g_{0})-f}{1/g_{0}}\ (mod\ x^{2n})\\ \\ g\equiv g_{0}(1-ln(g_{0})+f)\ (mod\ x^{2n})

 

Part5:快速幂

已知f,k,求g\equiv f^k\ (mod\ x^n)

1.我们先根据快速幂的思想,发现一个两只log常数巨大的做法

2.ln(g)\equiv kln(f)

 

Part6:开根

已知f.求g\equiv f^{1/2}\ (mod\ x^n)

我们构造t(g)=g^2-f

\\g\equiv g_{0}-\frac{g_{0}^2-f}{2g_{0}}\ (mod\ x^{2n})\\ \\ g\equiv g_{0}/2+g_{0}^{-1}f/2\ (mod\ x^{2n})

 

Part7:除法(差点把他忘了

求逆即可

 

#150. 挑战多项式

就是多项式的综合模板

注:这里的多项式开根常数项要用二次剩余求,但是博主不会二次剩余,于是三岁神仙qy就交给我单次求的BSGS(怒膜一发)

其实就是利用原根性质把x^2化成g^r即可

由于博主用的是vector而且博主代码自带巨大常数,所以就跑的奇慢无比

#include<bits/stdc++.h>
#define ll long long
#define mk(x,y) make_pair(x,y)
#define pb(x) push_back(x)
#define cs const
using namespace std;
cs int g=3;
const int N=6e5+10;
const int mod=998244353;
typedef vector<int> poly;
int rev[N],inv[N];
int n,m,len,d,x,k;
poly a;
int mul(int x,int y){return (ll)x*y%mod;}
int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
int dec(int x,int y){return x-y>=0?x-y:x-y+mod;}
int ksm(int x,int y){
    ll ans=1;
    for (;y;y>>=1,x=mul(x,x)) if (y&1) ans=mul(ans,x);
    return ans;
}
int read(){
	int f=1,x=0; char c=getchar();
	while (c<'0'||c>'9'){if (c=='-')f=-1;c=getchar();}
	while (c>='0'&&c<='9'){x=add(mul(x,10),c-'0');c=getchar();}
	return x; 
}
void init(int x){
    len=1,d=0;
    while (len<x) {len<<=1;d++;}
    for (int i=0;i<len;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(d-1));
}
int BSGS(int X,int Y){
	int now=floor(sqrt(mod));
	int s=ksm(X,now);
	map<int,int>mp;
	int t=1;
	int sum=Y;
	for (int i=0;i<now;i++){
		mp[sum]=i; sum=mul(sum,X);
	}
	int s1=1;
    for (int i=0;i<mod;i+=now){
    	s1=mul(s1,s);
    	if (mp[s1]) return i+now-mp[s1];
	}
}
int lalala(int x){
	int now=BSGS(g,x);
	return ksm(g,now/2);
}
void out(poly a){
    for (int i=0;i<a.size();i++) printf("%d ",a[i]);
    puts("\n");
}
inline poly NTT(poly a,int t) {
    for (int i=0;i<a.size();i++) if (i<rev[i]) swap(a[i],a[rev[i]]);
    for (int i=1;i<a.size();i<<=1) {
      int s=(i<<1);
      int wn=ksm(g,(mod-1)/s);
      if (t==-1) wn=ksm(wn,mod-2);
      for (int j=0;j<a.size();j+=s) {
      	int w=1;
      	for (int k=j;k<j+i;k++) {
      	 	int x=a[k],y=mul(a[k+i],w);
      	 	a[k]=add(x,y); a[k+i]=dec(x,y);
      	 	w=mul(w,wn);
         }
      }
    }
    if (t==-1){
        ll w=ksm(a.size(),mod-2);
        for (int i=0;i<a.size();i++) a[i]=mul(a[i],w);
    }
    return a;
}
inline poly get_down(poly a){
    for (int i=0;i<a.size()-1;i++) a[i]=mul(a[i+1],i+1);
    a.pop_back();
    return a;
}
inline poly get_up(poly a){
    a.push_back(0);
    for (int i=a.size()-1;i>0;i--) a[i]=mul(a[i-1],inv[i]);
    a[0]=0;
    return a; 
}
inline poly operator +(poly a,poly b){
    a.resize(max(a.size(),b.size()));
    b.resize(max(a.size(),b.size()));
    for (int i=0;i<a.size();i++) a[i]=add(a[i],b[i]);
    return a; 
}
inline poly operator -(poly a,poly b){
    a.resize(max(a.size(),b.size()));
    b.resize(max(a.size(),b.size()));
    for (int i=0;i<a.size();i++) a[i]=dec(a[i],b[i]);
    return a;
}
inline poly operator *(poly a,int x){
    for (int i=0;i<a.size();i++) a[i]=mul(a[i],x);
    return a;
}
inline poly operator *(poly a,poly b){
    int n=a.size(),m=b.size(); 
    init(n+m-1);
    a.resize(len);
    b.resize(len);
    a=NTT(a,1); b=NTT(b,1);
    for (int i=0;i<a.size();i++) a[i]=mul(a[i],b[i]);
    a=NTT(a,-1);
    a.resize(n+m-1);
    return a;
}
inline poly get_inv(poly a){
    poly b,d;
    b.pb(ksm(a[0],mod-2)); d.pb(a[0]);
    int now=1;
    while (now<a.size()) {
        now<<=1; 
        poly c=b;
        c=c*c;
        for (int i=(now>>1);i<now&&i<a.size();i++) d.pb(a[i]);
        c=c*d;c.resize(now); 
        b=b*2;  b=b-c;
    }
    b.resize(a.size());
    return b;
}
inline poly ln(poly a){poly c=get_up(get_inv(a)*get_down(a));c.resize(a.size());return c;}
inline poly exp(poly a){
    poly b,d;
    b.pb(1); d.pb(a[0]);
    int now=1;
    while (now<a.size()){
      	now<<=1;
       	for (int i=(now>>1);i<now&&i<a.size();i++) d.pb(a[i]);
       	poly c=b;
       	c.resize(now);
       	c=ln(c)-d;
       	for (int i=0;i<c.size();i++) c[i]=(mod-c[i])%mod;
       	c[0]=add(c[0],1); 
       	b=b*c; b.resize(now); 
    }	
    b.resize(a.size());
    return b;
}
inline poly ksm(poly a,int k){return exp(ln(a)*k);}
inline poly Sqrt(poly a){
    poly b,d;
    b.pb(lalala(a[0])); d.pb(a[0]);
    b[0]=min(b[0],mod-b[0]);
    int now=1;
    while (now<a.size()){
        now<<=1; poly c=b;
        for (int i=(now>>1);i<now&&i<a.size();i++) d.pb(a[i]);
        c.resize(now);
        c=get_inv(c);
		c=c*d;c.resize(now);
        b=b+c;
        for (int i=0;i<now;i++) b[i]=mul(b[i],inv[2]);
    }
    b.resize(a.size());
    return b;
}
int main(){
//	freopen("da.in","r",stdin);
//	freopen("da.out","w",stdout);
    inv[0]=inv[1]=1;
    for (int i=2;i<N;i++) inv[i]=mul(inv[mod%i],(mod-mod/i));
    scanf("%d",&n); k=read();
    for (int i=0;i<=n;i++) {
        scanf("%d",&x); a.pb(x);
    }
    poly b=a;
    a=Sqrt(a);a=get_inv(a);a=get_up(a);
    a=exp(a); b[0]=2;
	a=b-a;a=ln(a);a[0]=1;
	a=ksm(a,k);a=get_down(a);
	a.resize(n);
	out(a); 
//    fclose(stdin);
//    fclose(stdout);
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值