多项式板子 [vector<int>版本]

偷的板子
跑起来非常非常快。

#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>

using namespace std;

int read(){
    
    
	int res = 0 , flag = 1 ;
	char c = getchar() ;
	while(!isdigit(c)){
    
    
		if(c == '-') flag = -1 ;
		c = getchar() ;
	}
	while(isdigit(c)){
    
    
		res = (res << 1) + (res << 3) + (c ^ 48) ;
		c = getchar() ;
	}
	return res * flag ; 
}

void write(int x){
    
    
	if(x < 0) {
    
    
		putchar('-') ;
		x = - x ;
	}
	if(x >= 10) write(x / 10) ;
	putchar('0' + x % 10) ;
}

void write(int x , char c){
    
    
	write(x) ;
	putchar(c) ; 
}

// #define debug(x) cout<<"[debug]"#x<<"="<<x<<endl
typedef long long ll;
typedef long double ld;
typedef pair<int,int> pii;
const double eps=1e-8;
const int inf=0x3f3f3f3f;

#ifndef ONLINE_JUDGE
#define debug(...)
// #include<debug>
#else
#define debug(...)
#endif

const int N= 1000006;
namespace NTT
{
    
    
    typedef vector<ll> Poly;
    const int mod=998244353,G=3,Gi=332748118;
    const int M=2e6+1e5;
    int bit,tot;
    int rev[M];
    int inv[M];
    int init_inv=[](){
    
    
    inv[0]=inv[1]=1;
    for(int i=2;i<M;i++)
        inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
    return 0;
    }();
    ll qmi(ll a,ll b,ll p)
    {
    
    
        ll res=1;
        while(b)
        {
    
    
            if(b&1)
            res=res*a%p;

            a=a*a%p;
            b>>=1;
        }
        return res;
    }
    void NTT(Poly &a,int inv)
    {
    
    
        for(int i=0;i<tot;i++)
            if(i<rev[i]) swap(a[i],a[rev[i]]);
    
        for(int mid=1;mid<tot;mid*=2)
        {
    
    
            ll w1=qmi(inv==1?G:Gi,(mod-1)/(2*mid),mod);
            for(int i=0;i<tot;i+=mid*2)
            {
    
    
                ll wk=1;
                for(int j=0;j<mid;j++,wk=wk*w1%mod)
                {
    
    
                    ll x=a[i+j];
                    ll y=wk*a[i+j+mid]%mod;
                    a[i+j]=(x+y)%mod;
                    a[i+j+mid]=(x-y+mod)%mod;
                }
            }
        }
    
        if(inv==-1)//就不用后面除了
        {
    
    
            ll intot=qmi(tot,mod-2,mod);
            for(int i=0;i<tot;i++)
            {
    
    
                a[i]=a[i]*intot%mod;
            }
        }
    }
    Poly mul(Poly a,Poly b)//deg是系数的数量,所以有0~deg-1次项
    {
    
    
        int deg=(int)a.size()+b.size()-1;
        bit=0;
        while((1<<bit)<deg) bit++;//至少要系数的数量
        tot=1<<bit; //系数项为0~tot-1
        for(int i=0;i<tot;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));

        Poly c(tot);
        a.resize(tot),b.resize(tot);
        NTT(a,1),NTT(b,1);
        for(int i=0;i<tot;i++) c[i]=a[i]*b[i]%mod;
        NTT(c,-1);
        // c.resize(1000001);
        return c;
    }
    Poly operator *(Poly &a,Poly &b)
    {
    
    
        return mul(a,b);
    }
    Poly operator *(Poly &a,int &t)
    {
    
    
        Poly res;
        for(int i=0;i<a.size();i++) res.push_back(1ll*a[i]*t%mod);
        return res;
    }
    Poly operator *(Poly &a,ll &t)
    {
    
    
        Poly res;
        for(int i=0;i<a.size();i++) res.push_back(a[i]*t%mod);
        return res;
    }
    Poly operator +(Poly &a,Poly &b)
    {
    
    
        Poly res(a);
        res.resize(max(a.size(),b.size()));
        for(int i=0;i<b.size();i++) res[i]=(res[i]+b[i])%mod;
        return res;
    }
    Poly operator -(Poly &a,Poly &b)
    {
    
    
        Poly res(a);
        res.resize(max(a.size(),b.size()));
        for(int i=0;i<b.size();i++) res[i]=(res[i]-b[i]+mod)%mod;
        return res;
    }
    Poly Inv(Poly &f,int deg)//多项式f对于x^deg的逆元(注意rev[]等数组要开到2*deg的空间级别,f[]要开deg级别)
    {
    
    
        if(deg==1) return Poly(1,qmi(f[0],mod-2,mod));

        Poly B=Inv(f,(deg+1)>>1);//上一个逆元
        Poly A(f.begin(),f.begin()+deg);

        bit=0;
        while((1<<bit)<(deg<<1)) bit++;//至少要系数的数量
        tot=1<<bit; //系数项为0~tot-1
        for(int i=0;i<tot;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
        
        A.resize(tot),B.resize(tot);
        NTT(A,1),NTT(B,1);
        for(int i=0;i<tot;i++)
        A[i]=B[i]*(2-A[i]*B[i]%mod+mod)%mod;
        NTT(A,-1);
        A.resize(deg);
        return A;
    }
    Poly cdq_ntt(int l,int r,vector<Poly> &f)
    {
    
    
        if(l==r) return f[l];
        int mid=l+r>>1;
        return mul(cdq_ntt(l,mid,f),cdq_ntt(mid+1,r,f));
    }
    namespace Cipolla
    {
    
    
        int W;
        struct cp
        {
    
    
            ll x,y;
            cp(ll x=0,ll y=0): x(x),y(y) {
    
    }
            cp operator+ (const cp _)const{
    
    
                return {
    
    (x+_.x)%mod,(y+_.y)%mod};
            } 
            cp operator* (const cp _)const{
    
    
                return {
    
    (x*_.x%mod+y*_.y%mod*W%mod)%mod,(x*_.y+y*_.x)%mod};
            }
        };
        cp qmi(cp a,int b)
        {
    
    
            cp res=1;
            while(b)
            {
    
    
                if(b&1) res=res*a;

                a=a*a;
                b>>=1;
            }
            return res;
        }
        int cipolla(int n)
        {
    
    
            if(qmi(n,(mod-1)>>1).x!=1)
            {
    
    
                return -1;
            }
            int a=rand()%mod;
            while(!a||qmi((1ll*a*a-n+mod)%mod,(mod-1)>>1).x==1)
            {
    
    
                a=rand()%mod;
            }
            W=(1ll*a*a-n+mod)%mod;

            int x=qmi(cp(a,1),(mod+1)>>1).x;
            if(x>mod-x) x=mod-x;
            return x;
        }
    }
    Poly Sqrt(Poly &A,int deg)
    {
    
    
        if(deg==1)
        {
    
    
            return {
    
    Cipolla::cipolla(A[0])};//A[0]=1修改这里即可
        }

        Poly f0=Sqrt(A,(deg+1)>>1);
        f0.resize(deg);
        Poly inf0=Inv(f0,deg);
        Poly temp(A.begin(),A.begin()+deg);
        temp=mul(inf0,temp);
        temp.resize(deg);
        for(int i=0;i<deg;i++) f0[i]=(f0[i]+temp[i])*inv[2]%mod;

        return f0;
    }
    Poly Deriv(Poly f)//求导
    {
    
    
        for(int i=0;i<f.size();i++) f[i]=f[i+1]*(i+1)%mod;
        f.pop_back();
        return f;
    }
    Poly Integ(Poly f)//积分
    {
    
    
        f.push_back(0);
        for(int i=f.size()-1;i>=1;i--) f[i]=f[i-1]*inv[i]%mod;
        f[0]=0;
        return f;
    }
    Poly Ln(Poly f,int deg)//f[0]=1
    {
    
    
        f=mul(Deriv(f),Inv(f,deg));
        f.resize(deg-1);
        return Integ(f);
    }
    Poly Exp(Poly &A,int deg)//A[0]=0,记得至少开deg大小
    {
    
    
        if(deg==1) return {
    
    1};
        Poly f0=Exp(A,(deg+1)>>1);
        Poly temp=f0;
        temp.resize(deg);
        temp=Ln(temp,deg);
        for(int i=0;i<deg;i++) temp[i]=(A[i]-temp[i]+mod)%mod;
        temp[0]=(temp[0]+1)%mod;
        temp=mul(f0,temp);
        temp.resize(deg);
        return temp;
    }
    Poly qmi_ntt(Poly A,int k,int deg=-1)//A(x)^k且A[0]=1
    {
    
    
        if(deg==-1) deg=(A.size()-1)*k+1;
        A.resize(deg);
        A=Ln(A,deg);
        A=A*k;
        A=Exp(A,deg);
        return A;
    }
    Poly qmi_ntt(Poly A,string s,int deg=-1)//A(x)^k
    {
    
    
        ll k=0;//mod (p)
        ll kk=0;//mod (p-1),即phi(p)
        bool ty=false;
        for(int i=0;i<s.size();i++)
        {
    
    
            k=(1ll*k*10+(s[i]-'0'));
            if(k>=mod) k%=mod,ty=true;
            kk=(1ll*kk*10+(s[i]-'0'))%(mod-1);
        }
        if(deg==-1) deg=(A.size()-1)*k+1;
        A.resize(deg);
        int n=A.size();
        int t=0;
        while(t<n&&!A[t]) t++;

        if(t==n||ty&&t>=1)
        {
    
    
            return Poly(n,0);
        }
        ll temp=qmi(A[t],mod-2,mod);
        Poly B;
        for(int i=t;i<A.size();i++) B.push_back(A[i]*temp%mod);
        B=Ln(B,B.size());
        B=B*k;
        B=Exp(B,B.size());
        B.resize(n);
        Poly res(n);
        temp=qmi(A[t],kk,mod);
        for(ll i=1ll*t*k;i<n;i++) res[i]=B[i-1ll*t*k]*temp%mod;
        return res;
    }
    Poly psqmi_ntt(Poly A,int k)
    {
    
    
        Poly res(1,1);
        while(k)
        {
    
    
            if(k&1) res=res*A;
            A=A*A;
            k>>=1;
        }
        return res;
    }
}
using namespace NTT;

int main()
{
    
    
	/* P1919 A*B
	string a , b ;
	cin >> a >> b ;
	int n = a.size() , m = b.size() ;
	Poly A(n) , B(m) ;
	for(int i = 0 ; i < n ; i ++) A[i] = a[n - i - 1] - '0' ;
	for(int i = 0 ; i < m ; i ++) B[i] = b[m - i - 1] - '0' ;
	Poly c = A * B ;
	for(int i = 0 ; i < c.size() ; i ++){
		if(c[i] >= 10) c[i + 1] += c[i] / 10 , c[i] %= 10 ;
	}
	while(c.size() > 1 && c.back() == 0) c.pop_back() ;
	for(int i = c.size() - 1 ; i >= 0 ; i --)
		write(c[i]) ; 
	*/
	
	
	/* P4238 【模板】多项式乘法逆
		int n = read() ;
		Poly A(n) ;
		for(int i = 0 ; i < n ; i ++) A[i] = read() ;
		Poly B = Inv(A , n) ;
		for(int i = 0 ; i < n ; i ++) write(B[i] , ' ') ; 
	*/
	
	/* P5205 【模板】多项式开根
		int n = read() ;
		Poly A(n) ;
		for(int i = 0 ; i < n ; i ++) A[i] = read() ;
		Poly B = Sqrt(A , n) ; 
		for(int i = 0 ; i < n ; i ++) write(B[i] , ' ') ;
	*/
	
	/* P4725 【模板】多项式对数函数(多项式 ln)
		int n = read() ;
		Poly A(n) ;
		for(int i = 0 ; i < n ; i ++) A[i] = read() ;
		Poly B = Ln(A , n) ; 
		for(int i = 0 ; i < n ; i ++) write(B[i] , ' ') ;
	*/
	
	/* P4726 【模板】多项式指数函数(多项式 exp)
		int n = read() ;
		Poly A(n) ;
		for(int i = 0 ; i < n ; i ++) A[i] = read() ;
		Poly B = Exp(A , n) ; 
		for(int i = 0 ; i < n ; i ++) write(B[i] , ' ') ;
	*/
	
	/* P5245 【模板】多项式快速幂
		int n = read() ;
		string k ;  cin >> k ;
		Poly A(n) ;
		for(int i = 0 ; i < n ; i ++) A[i] = read() ;
		Poly B = qmi_ntt(A , k , n) ;
		for(int i = 0 ; i < n ; i ++) write(B[i] , ' ') ;
	*/
}

猜你喜欢

转载自blog.csdn.net/qq_52358098/article/details/129120568