码迷,mamicode.com
首页 > 其他好文 > 详细

多项式全家桶(纯模板)

时间:2020-12-28 11:13:59      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:namespace   多点   struct   exp   sqrt   tin   check   type   函数   

已经完成的:

  • 多项式乘法
  • 多项式乘法逆
  • 多项式\(\ln\)
  • 多项式\(\exp\)
  • 多项式开根(\(a_0\)为二次剩余)
  • 多项式快速幂(\(a_0\)可以不为1)
  • 多项式三角函数(\(\sin,\cos\))
  • 多项式除法、取模
  • 分治\(FFT\)

还未完成的

  • 任意模数\(NTT\)(\(MTT\))
  • 多项式多点求值
  • 多项式快速插值
  • 常系数(非)齐次线性递推
  • 多项式复合逆
#include<bits/stdc++.h>
using namespace std;
const int N=(1<<21)+10;
const int mod=998244353;
const int gg=3;
const int giv=(mod+1)/3;
typedef long long ll;

namespace Math{
	int inv[N],tp=2;
	inline void init(int n){
		if(tp==2) inv[0]=inv[1]=1;
		for(tp;tp<=n;++tp)
			inv[tp]=1ll*(mod-mod/tp)*inv[mod%tp]%mod; 
	}
	inline int ksm(int a,ll b){
		int ret=1;
		for(;b;a=1ll*a*a%mod,b>>=1) (b&1)&&(ret=1ll*ret*a%mod);
		return ret;
	}
	inline int add(int x,int y){return (x+y>=mod)?x+y-mod:x+y;}
	inline int dec(int x,int y){return (x-y<0)?x-y+mod:x-y;}
}
using namespace Math;

namespace Container{
	struct poly{
		vector<int>v;
		inline int& operator[](int x){while(x>=v.size())v.push_back(0);return v[x];}
		inline poly(int x=0):v(1){v[0]=x;}
		inline int size(){return v.size();}
		inline void resize(int x){v.resize(x);}
		inline void mem(int l,int r,int x){fill(v.begin()+l,v.begin()+r+1,x);}
		
	};
	inline poly operator +(poly x,poly y){
		int mx=max(x.size(),y.size());
		for(int i=0;i<mx;++i) x[i]=add(x[i],y[i]);
		return x;
	}
	inline poly operator -(poly x,poly y){
		int mx=max(x.size(),y.size());
		for(int i=0;i<mx;++i) x[i]=dec(x[i],y[i]);
		return x;
	}
	inline poly operator *(poly x,poly y){
		int mx=max(x.size(),y.size());
		for(int i=0;i<mx;++i) x[i]=1ll*x[i]*y[i]%mod;
		return x;
	}
	inline poly operator *(poly x,int y){
		for(int i=0;i<x.size();++i) x[i]=1ll*x[i]*y%mod;
		return x;
	}
}
using namespace Container;

namespace basic{
	int r[N],Wn[N];
	inline void NTT(int lim,poly& f,int tp){
		for(int i=0;i<lim;++i) if(i<r[i]) swap(f[i],f[r[i]]);
		for(int mid=1;mid<lim;mid<<=1){
			int len=mid<<1,wn=ksm(tp==1?gg:giv,(mod-1)/len);
			Wn[0]=1;for(int i=1;i<mid;++i) Wn[i]=1ll*Wn[i-1]*wn%mod;
			for(int l=0;l+len-1<lim;l+=len){
				for(int k=l;k<=l+mid-1;++k){
					int w1=f[k],w2=1ll*Wn[k-l]*f[k+mid]%mod;
					f[k]=add(w1,w2);f[k+mid]=dec(w1,w2);
				}
			}
		}
	}
	inline poly poly_mul(int n,int m,poly f,poly g){
		int lim=1,len=0;
		while(lim<(n+m)) lim<<=1,len++;
		for(int i=0;i<lim;++i) r[i]=(r[i>>1]>>1)|((i&1)<<(len-1));
		if(f.size()>n) f.mem(n,min(lim,f.size())-1,0);
		if(g.size()>m) g.mem(m,min(lim,g.size())-1,0);
		NTT(lim,f,1);NTT(lim,g,1);
		for(int i=0;i<lim;++i) f[i]=1ll*f[i]*g[i]%mod;
		NTT(lim,f,-1);
		int iv=ksm(lim,mod-2);
		for(int i=0;i<lim;++i) f[i]=1ll*f[i]*iv%mod;
		return f;
	}
	inline void getdao(int n,poly& f){
		for(int i=1;i<n;++i){
			int t=f[i];
			f[i-1]=1ll*i*t%mod;
		}
		f[n-1]=0;
	}
	inline void jifen(int n,poly& f){
		init(n);
		for(int i=n-1;i;--i) f[i]=1ll*inv[i]*f[i-1]%mod;
		f[0]=0;
	}
	inline void get(int x,poly& f){
		for(int i=0;i<x;++i) scanf("%d",&f[i]);
	}
	inline void print(int x,poly f){
		for(int i=0;i<x;++i) printf("%d ",f[i]);puts("");
	}
}
using namespace basic;

namespace Cipolla{
	int I,fl=0;
	struct pt{
		int a,b;
		pt(int _a=0,int _b=0){a=_a;b=_b;}
	};
	inline pt operator *(pt x,pt y){
		pt ret;
		ret.a=add(1ll*x.a*y.a%mod,1ll*x.b*y.b%mod*I%mod);
		ret.b=add(1ll*x.a*y.b%mod,1ll*x.b*y.a%mod);
		return ret;
	}
	inline bool check(int x){
		return ksm(x,(mod-1)/2)==1;
	}
	inline int random(){
		return 1ll*rand()*rand()%mod;
	}
	inline pt qpow(pt a,int b){
		pt ret=pt(1,0);
		for(;b;a=a*a,b>>=1) if(b&1) ret=ret*a;
		return ret;
	}
	inline int cipolla(int n){
		if(!fl) srand(time(0)),fl=1;
		if(!check(n)) return 0;
		int a=random();
		while(!a||check(dec(1ll*a*a%mod,n))) a=random();
		I=dec(1ll*a*a%mod,n);
		int ans=qpow(pt(a,1),(mod+1)/2).a;
		return min(ans,mod-ans);
	}
}
using namespace Cipolla;

namespace Poly{
	inline poly getinv(int n,poly f){
		if(n==1){poly g;g[0]=ksm(f[0],mod-2);return g;}
		poly g=getinv(n+1>>1,f);poly p=g;
		
		int lim=1,len=0;
		while(lim<(n<<1)) lim<<=1,len++;
		for(int i=0;i<lim;++i) r[i]=(r[i>>1]>>1)|((i&1)<<(len-1));
		if(f.size()>n) f.mem(n,min(lim,f.size())-1,0);
		if(p.size()>n) p.mem(n,min(lim,g.size())-1,0);
		
		NTT(lim,f,1);NTT(lim,p,1);
		for(int i=0;i<lim;++i) f[i]=1ll*f[i]*p[i]%mod*p[i]%mod;
		NTT(lim,f,-1);
		int iv=ksm(lim,mod-2);
		poly h;
		for(int i=0;i<n;++i) h[i]=dec(2ll*g[i]%mod,1ll*f[i]*iv%mod);
		return h;
	} 
	inline poly getln(int n,poly f){
		poly g=getinv(n,f);getdao(n,f);
		poly h=poly_mul(n,n,f,g);
		jifen(n,h);
		return h;
	}
	inline poly getexp(int n,poly f){
		if(n==1){poly g;g[0]=1;return g;}
		poly g=getexp(n+1>>1,f),B=getln(n,g);
		for(int i=0;i<n;++i) B[i]=dec((i==0),dec(B[i],f[i]));
		return poly_mul(n,n,g,B);
	}
	inline poly Pow(int n,int k,poly f){
		poly g=getln(n,f);
		for(int i=0;i<n;++i) g[i]=1ll*g[i]*k%mod;
		return getexp(n,g);
	}
	inline poly Sqrt(int n,poly f){
		if(n==1){poly g;g[0]=cipolla(f[0]);return g;}
		poly g=Sqrt((n+1)>>1,f);
		poly p=getinv(n,g);
		poly h=poly_mul(n,n,p,f);
		for(int i=0;i<n;++i) h[i]=1ll*((mod+1)/2)*add(h[i],g[i])%mod;
		return h;		
	}
	inline poly rev(int n,poly f){
		for(int i=0;i<(n>>1);++i) swap(f[i],f[n-i-1]);
		return f;
	}
	inline poly divide(int n,int m,poly A,poly B){
		A=rev(n,A);B=rev(m,B);
		B=getinv(n-m+1,B);
		poly C=poly_mul(n-m+1,n-m+1,A,B);
		return rev(n-m+1,C);
	}
	inline poly Mod(int n,int m,poly A,poly B,poly C){
		B=poly_mul(m,n-m+1,B,C);
		for(int i=0;i<m-1;++i) A[i]=dec(A[i],B[i]);
		return A;
	}
	inline poly Mod(int n,int m,poly A,poly B){
		poly C=divide(n,m,A,B);
		return Mod(n,m,A,B,C);
	}
	inline poly Sin(int n,poly f){
		int II=ksm(gg,(mod-1)/4);
		poly g1=getexp(n,f*II),g2=getexp(n,f*(mod-II));
		return (g1-g2)*ksm(add(II,II),mod-2);
	}
	inline poly Cos(int n,poly f){
		int II=ksm(gg,(mod-1)/4);
		poly g1=getexp(n,f*II),g2=getexp(n,f*(mod-II));
		return (g1+g2)*((mod+1)/2);
	}
} 
using namespace Poly;

int n,m,a[N],ans[N];poly f,g;
namespace fastpow{
	int flag,k,kk,ne;
	poly f,ret;
	char s[N];
	inline int readpow1(){
		long long x=0,f=1;int len=strlen(s+1);
		for(int i=1;i<=len;++i){char ch=s[i];x=((x<<3)+(x<<1)+(ch^48));if(x>=n) flag=1;while(x>=mod) x-=mod;}
		return f==-1?mod-x:x;
	}
	inline int readpow2(){
		long long x=0,f=1;int m=mod-1,len=strlen(s+1);
		for(int i=1;i<=len;++i){char ch=s[i];x=((x<<3)+(x<<1)+(ch^48));while(x>=m) x-=m;}
		return f==-1?m-x:x;
	}
	inline int init(int &n,poly& f){
		int now=0;
		while(f[now]==0) ++now;
		int iv=ksm(f[now],mod-2),ans=ksm(f[now],kk);
		for(int i=now;i<n;++i) f[i-now]=1ll*f[i]*iv%mod;
		long long x=1ll*now*k;
		if(x>=n||(flag&&now!=0)){
			for(int i=0;i<n;++i) ret[i]=0;
			return -1;
		} 
		for(int i=0;i<x;++i) ret[i]=0;
		ne=x;
		n-=now;
		return ans;
	}//init:将f的最低非零系数变为1 
	inline poly notone_pow(int n,int k,poly f){
		ne=n;kk=k;int t=n;int p=init(n,f);
		if(p==-1) return ret;
		f=Poly::Pow(n,k,f);
		for(int i=ne;i<t;++i) ret[i]=f[i-ne];
		return ret;
	}
}

namespace DCFFT{
	inline void solve(int l,int r){
		if(l>=r) return ;
		int mid=(l+r)>>1;
		solve(l,mid);
		poly f;for(int i=l;i<=mid;++i) f[i-l]=ans[i];
		poly h=poly_mul(mid-l+1,r-l+1,f,g);
		for(int i=mid+1;i<=r;++i) ans[i]=add(ans[i],h[i-l]); 
		solve(mid+1,r);
	}
} 
//Tip:上面所有的n都表示n-1次多项式 
int main(){
	return 0;
} 

多项式全家桶(纯模板)

标签:namespace   多点   struct   exp   sqrt   tin   check   type   函数   

原文地址:https://www.cnblogs.com/tqxboomzero/p/14170694.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!