多项式全(?)家桶

之前写的板子太丑了,封装的也不好,重新贴一遍吧。

主函数是多项式取余那题的,不关键。

代码

点击查看代码
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define maxn 400010
#define ll long long
#define mod 998244353
using namespace std;
const ll g=3;
ll qpow(ll x,int p){
    ll base,ans;
    for(base=x,ans=1;p;p>>=1,base=base*base%mod){
        if(p&1) ans=ans*base%mod;
    }
    return ans;
}
ll inv(ll x){
    return qpow(x,mod-2);
}
ll sqr(ll x){
    return 1;
}
void read(ll &x){
    x=0;
    char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9'){
        x=x*10+c-'0';
        c=getchar();
    }
}
void write(ll x){
    char s[30];
    int c=0;
    if(!x){
        printf("0");
        return;
    }
    while(x){
        s[++c]=x%10+'0';
        x/=10;
    }
    for(int i=c;i>=1;--i) putchar(s[i]);
}
namespace NTT{
    static ll A[maxn],B[maxn],w[maxn];
    int pos[maxn];
    int init(int n){
        int lg=0;
        while((1<<lg)<n) ++lg;
        for(int i=1;i<(1<<lg);++i) pos[i]=(pos[i>>1]>>1)|((1&i)<<(lg-1));
        return lg;
    }
    void ntt(ll *L,int N,int type){
        for(int i=0;i<N;++i){
            if(i<pos[i]) swap(L[i],L[pos[i]]);
        }
        w[0]=1;w[1]=qpow(g,(mod-1)/N);
        if(type<0) w[1]=inv(w[1]);
        for(int i=2;i<N;++i) w[i]=w[i-1]*w[1]%mod;
        for(int d=1,t=N>>1;d<N;d<<=1,t>>=1){
            for(int i=0;i<N;i+=(d<<1)){
                for(int j=i;j<i+d;++j){
                    ll tmp=w[(j-i)*t]*L[j+d]%mod;
                    L[j+d]=(L[j]-tmp+mod)%mod;
                    L[j]=(L[j]+tmp)%mod;
                }
            }
        }
    }
    void multi(ll *L1,int n,ll *L2,int m,ll *L3){
        int lg=init(n+m-1),len=1<<lg;
        for(int i=0;i<len;++i) A[i]=i<n?L1[i]:0;
        for(int i=0;i<len;++i) B[i]=i<m?L2[i]:0;
        ntt(A,len,1);ntt(B,len,1);
        for(int i=0;i<len;++i) L3[i]=A[i]*B[i]%mod;
        ntt(L3,len,-1);
        ll t=inv(len);
        for(int i=0;i<len;++i) L3[i]=L3[i]*t%mod;
    }
};
namespace poly{
    void Diff(ll *L,int n){//求导
        for(int i=0;i<n;++i) L[i]=L[i+1]*(i+1)%mod;
        L[n-1]=0;
    }
    void Int(ll *L,int n){//积分
        for(int i=n;i>0;--i) L[i]=L[i-1]*inv(i)%mod;
        L[0]=0;
    }
    void Rev(ll *L,int n){
        for(int i=0;i<n-i-1;++i) swap(L[i],L[n-i-1]);
    }
    void Inv(ll *L,int n){//多项式乘法逆
        static ll A[maxn],B[maxn];
        int lg=NTT::init(n),len;
        for(int i=0;i<(1<<lg+1);++i) A[i]=B[i]=0;
        B[0]=inv(L[0]);
        for(int i=0,len=1;i<=lg;++i,len<<=1){
            for(int j=0;j<(len<<1);++j) A[j]=j<len?L[j]:0;
            NTT::init(len<<1);
            NTT::ntt(A,len<<1,1);NTT::ntt(B,len<<1,1);
            for(int j=0;j<(len<<1);++j) B[j]=(mod+2-A[j]*B[j]%mod)%mod*B[j]%mod;
            NTT::ntt(B,len<<1,-1);
            for(int j=0;j<len;++j) B[j]=B[j]*inv(len<<1)%mod;
            for(int j=len;j<(len<<1);++j) B[j]=0;
        }
        for(int i=0;i<(1<<lg);++i) L[i]=i<n?B[i]:0;
    }
    void Ln(ll *L,int n){//多项式对数函数
        static ll A[maxn],B[maxn],C[maxn];
        int lg=NTT::init(n);
        for(int i=0;i<(1<<lg+1);++i) A[i]=B[i]=C[i]=0;
        for(int i=0;i<n;++i) A[i]=L[i];
        Diff(A,n);
        for(int i=0;i<n;++i) B[i]=L[i];
        Inv(B,n);
        NTT::multi(A,n-1,B,n,C);
        Int(C,2*n);
        for(int i=0;i<n;++i) L[i]=C[i];
    }
    void Exp(ll *L,int n){//多项式指数函数
        static ll A[maxn],B[maxn],ln[maxn];
        int lg=NTT::init(n),len;
        for(int i=0;i<(1<<lg+1);++i) A[i]=B[i]=ln[i]=0;
        B[0]=1;
        for(int i=0,len=1;i<=lg;++i,len<<=1){
            for(int j=0;j<(len<<1);++j) A[j]=j<len?L[j]:0;
            for(int j=0;j<(len<<1);++j) ln[j]=j<len?B[j]:0;
            Ln(ln,len);
            NTT::init(len<<1);
            NTT::ntt(B,len<<1,1);
            NTT::ntt(ln,len<<1,1);
            NTT::ntt(A,len<<1,1);
            for(int j=0;j<(len<<1);++j) B[j]=(1-ln[j]+A[j]+mod)%mod*B[j]%mod;
            NTT::ntt(B,len<<1,-1);
            for(int j=0;j<(len<<1);++j) B[j]=B[j]*inv(len<<1)%mod;
        }
        for(int i=0;i<(1<<lg);++i) L[i]=i<n?B[i]:0;
    }
    void Cos(ll *L,int n){//多项式三角函数cos
        static ll A[maxn],B[maxn];
        ll j=qpow(g,mod-1>>2);
        for(int i=0;i<n;++i) A[i]=B[i]=0;
        for(int i=0;i<n;++i) A[i]=L[i]*j%mod;
        Exp(A,n);
        for(int i=0;i<n;++i) B[i]=A[i];
        Inv(B,n);
        ll t=inv(2);
        for(int i=0;i<n;++i) L[i]=(A[i]+B[i])%mod*t%mod;
    }
    void Sin(ll *L,int n){//多项式三角函数sin
        static ll A[maxn],B[maxn];
        ll j=qpow(g,mod-1>>2);
        for(int i=0;i<n;++i) A[i]=B[i]=0;
        for(int i=0;i<n;++i) A[i]=L[i]*j%mod;
        Exp(A,n);
        for(int i=0;i<n;++i) B[i]=A[i];
        Inv(B,n);
        ll t=inv(2*j%mod);
        for(int i=0;i<n;++i) L[i]=(A[i]-B[i]+mod)%mod*t%mod;
    }
    void Kasumi(ll *L,int n,int k){//多项式幂函数
        static ll A[maxn];
        for(int i=0;i<n;++i) A[i]=L[i];
        Ln(A,n);
        for(int i=0;i<n;++i) A[i]=A[i]*k%mod;
        Exp(A,n);
        for(int i=0;i<n;++i) L[i]=A[i];
    }
    void Sqrt(ll *L,int n){//多项式开根(默认常数项为1,否则sqr函数要写BSGS)
        static ll A[maxn],B[maxn],iB[maxn];
        int lg=NTT::init(n),len;
        for(int i=0;i<(1<<lg+1);++i) A[i]=B[i]=iB[i]=0;
        B[0]=sqr(A[0]);
        for(int i=0,len=1;i<=lg;++i,len<<=1){
            for(int j=0;j<(len<<1);++j) A[j]=j<len?L[j]:0;
            for(int j=0;j<(len<<1);++j) iB[j]=j<len?B[j]:0;
            Inv(iB,len);
            NTT::init(len<<1);
            NTT::ntt(A,len<<1,1);
            NTT::ntt(B,len<<1,1);
            NTT::ntt(iB,len<<1,1);
            ll t=inv(2);
            for(int j=0;j<(len<<1);++j) B[j]=(B[j]+A[j]*iB[j]%mod)*t%mod;
            NTT::ntt(B,len<<1,-1);
            t=inv(len<<1);
            for(int j=0;j<(len<<1);++j) B[j]=B[j]*t%mod;
        }
        for(int i=0;i<n;++i) L[i]=B[i];
    }
    void Mod(ll *L1,int n,ll *L2,int m,ll *L3,ll *L4){//L1对L2取模,商存到L3中,余数在L4中
        static ll Q[maxn],R[maxn],F[maxn],G[maxn];
        for(int i=0;i<n;++i) F[i]=L1[i];
        for(int i=0;i<m;++i) G[i]=L2[i];
        Rev(F,n),Rev(G,m);
        Inv(G,n-m+1);
        NTT::multi(G,n-m+1,F,n-m+1,Q);
        Rev(Q,n-m+1);
        for(int i=0;i<n-m+1;++i) L3[i]=Q[i];//计算商式

        for(int i=0;i<n;++i) F[i]=L1[i];
        for(int i=0;i<n;++i) G[i]=i<m?L2[i]:0;
        for(int i=n-m+1;i<n;++i) Q[i]=0;
        NTT::multi(G,m,Q,n-m+1,R);
        for(int i=0;i<m;++i) R[i]=(F[i]-R[i]+mod)%mod;
        for(int i=0;i<m;++i) L4[i]=R[i];//计算余式
    }
};
ll a[maxn],b[maxn],c[maxn],d[maxn];
int main(){
    int i,n,k,m;
    freopen("test.in","r",stdin);
    freopen("test.out","w",stdout);
    scanf("%d%d",&n,&m);
    m++,n++;
    for(i=0;i<n;++i) read(a[i]);
    for(i=0;i<m;++i) read(b[i]);
    poly::Mod(a,n,b,m,c,d);
    for(i=0;i<n-m+1;++i) write(c[i]),putchar(' ');
    putchar('\n');
    for(i=0;i<m-1;++i) write(d[i]),putchar(' ');
    return 0;
}
posted @ 2022-09-07 18:47  文艺平衡树  阅读(28)  评论(0编辑  收藏  举报