poly 全家福

const int P=998244353,Pi=499122177;

inline int inc(int a,int b){return(a+=b)>=P?a-P:a;}
inline int dec(int a,int b){return(a-=b)<0?a+P:a;}
inline int mul(int a,int b){int s=1ll*a*b%P;return s<0?s+P:s;}
inline void add(int &a,int b){(a+=b)>=P?a-=P:1;}
inline void sub(int &a,int b){(a-=b)<0?a+=P:1;}
inline int sgn(int x){return x&1?P-1:1;}
inline int qpow(int a,int b){int res=1;while(b){if(b&1)res=mul(res,a);a=mul(a,a);b>>=1;}return res;}

namespace Poly{

    const int ng=3;
    const int ngi=(P+1)/3;

    const int L=20;
    const int N=1<<L;

    int w[N],pinv[N];

    inline void init_w(){
        w[0]=pinv[1]=1;
        for(int i=0;i<L;i++)
            w[1<<i]=qpow(ng,(P-1)>>(i+2));
        for(int i=2;i<N;i++){
            w[i]=mul(w[i&-i],w[i&i-1]);
            pinv[i]=P-mul(P/i,pinv[P%i]);
        }
    }

    inline void dif(int *f,int n){
        int t,k,*tw,*tf,*pf;
        for(k=n>>1;k;k>>=1){
            for(tw=w,tf=f;tf!=f+n;tw++,tf+=k<<1){
                for(pf=tf;pf!=tf+k;pf++){
                    t=mul(pf[k],*tw);
                    pf[k]=dec(*pf,t);
                    add(*pf,t);
                }
            }
        }
    }

    inline void dit(int *f,int n){
        int t,k,*tw,*tf,*pf;
        for(k=1;k<n;k<<=1){
            for(tw=w,tf=f;tf!=f+n;tw++,tf+=k<<1){
                for(pf=tf;pf!=tf+k;pf++){
                    t=pf[k];
                    pf[k]=mul(dec(*pf,t),*tw);
                    add(*pf,t);
                }
            }
        }
        int iv=P-(P-1)/n;
        for(int i=0;i<n;i++)
            f[i]=mul(f[i],iv);
        reverse(f+1,f+n);
    }

    int f0[N];

    struct poly{

        vector<int>a;
        inline int size(){return(int)a.size();}
        inline int& operator[](int i){return a[i];}
        inline void clear(){a.clear();}
        inline void resize(int n){a.resize(n);}

        inline poly(int n=0,int x=0){a.resize(n,x);}
        inline poly(const vector<int>&o){a=o;}
        inline poly(const poly &o){a=o.a;}

		inline void print(){
            int n=size();poly a=*this;
            for(int i=0;i<n;i++)write(a[i]),putchar(' ');puts("");
        }

        inline void operator+=(poly b){
            int n=size(),m=b.size();
            resize(max(n,m));
            for(int i=0;i<m;i++)
                add(a[i],b[i]);
        }

        inline friend poly operator+(poly a,poly b){
            a+=b;
            return a;
        }

        inline void operator-=(poly b){
            int n=size(),m=b.size();
            resize(max(n,m));
            for(int i=0;i<m;i++)
                sub(a[i],b[i]);
        }

        inline friend poly operator-(poly a,poly b){
            a-=b;
            return a;
        }

        inline void operator<<=(int k){
            int n=size();
            resize(n+k);
            for(int i=0;i<n;i++)
                a[i+k]=a[i];
            for(int i=0;i<k;i++)
                a[i]=0;
        }

        inline friend poly operator<<(poly a,int k){
            a<<=k;
            return a;
        }

        inline void operator*=(int b){
            int n=size();
            for(int i=0;i<n;i++)
                a[i]=mul(a[i],b);
        }

        inline friend poly operator*(poly a,int b){
            a*=b;
            return a;
        }

        inline void operator /=(int b){
            int n=size(),iv=qpow(b,P-2);
            for(int i=0;i<n;i++)
                a[i]=mul(a[i],iv);
        }

        inline friend poly operator/(poly a,int b){
            a/=b;
            return a;
        }

        inline void operator>>=(int k){
            int n=size();
            if(n<=k){
                *this=poly();
                return;
            }
            for(int i=k;i<n;i++)
                a[i-k]=a[i];
            resize(n-k);
        }

        inline friend poly operator>>(poly a,int k){
            a>>=k;
            return a;
        }

        inline poly diff(){
            int n=size();
            if(!n)
                return poly();
            poly res(n-1);
            for(int i=1;i<n;i++)
                res[i-1]=mul(a[i],i);
            return res;
        }

        inline poly intg(){
            int n=size();
            poly res(n+1);
            for(int i=0;i<n;i++)
                res[i+1]=mul(a[i],pinv[i+1]);
            return res;
        }

        inline void dft(){
            int n=size();
            assert(n==(n&-n));
            for(int i=0;i<n;i++)
                f0[i]=a[i];
            dif(f0,n);
            for(int i=0;i<n;i++)
                a[i]=f0[i];
        }

        inline void idft(){
            int n=size();
            assert(n==(n&-n));
            for(int i=0;i<n;i++)
                f0[i]=a[i];
            dit(f0,n);
            for(int i=0;i<n;i++)
                a[i]=f0[i];
        }

        inline void operator*=(poly b){
            int n=size(),m=b.size();
            int lim=1;
            while(lim<n+m-1)
                lim<<=1;
            resize(lim),dft();
            b.resize(lim),b.dft();
            for(int i=0;i<lim;i++)
                a[i]=mul(a[i],b[i]);
            idft(),resize(n+m-1);
        }

        inline friend poly operator*(poly a,poly b){
            a*=b;
            return a;
        }

        inline void operator/=(poly b){
            int n=size(),m=b.size();
            assert(n>=m);
            reverse(a.begin(),a.end());
            reverse(b.a.begin(),b.a.end());
            resize(n-m+1),b.resize(n-m+1);
            *this*=b.inv(),resize(n-m+1);
            reverse(a.begin(),a.end());
        }

        inline friend poly operator/(poly a,poly b){
            a/=b;
            return a;
        }
        
        inline void operator%=(poly b){
            int m=b.size();
            poly q=*this/b;
            *this-=q*b,resize(m-1);
        }

        inline friend poly operator%(poly a,poly b){
            a%=b;
            return a;
        }

        inline poly inv(){
            int n=size();
            assert(n);
            assert(a[0]);
            poly res(1),cp;
            res[0]=qpow(a[0],P-2);
            for(int o=2;o<(n<<1);o<<=1){
                cp=a;cp.resize(o);cp.resize(o<<1);
                res.resize(o<<1);
                res.dft(),cp.dft();
                for(int i=0;i<o<<1;i++)
                    res[i]=mul(res[i],dec(2,mul(res[i],cp[i])));
                res.idft(),res.resize(o);
            }
            res.resize(n);
            return res;
        }

        inline poly ln(){
            int n=size();
            assert(n);
            assert(a[0]==1);
            poly res=(diff()*inv()).intg();
            res.resize(n);
            return res;
        }

        inline poly exp(){
            int n=size();
            assert(n);
            assert(!a[0]);
            poly res(1),fln,cp;
            res[0]=1;
            for(int o=2;o<(n<<1);o<<=1){
                cp=a;cp.resize(o);cp.resize(o<<1);
                res.resize(o);fln=res.ln();fln.resize(o<<1);
                res.resize(o<<1);
                res.dft(),fln.dft(),cp.dft();
                for(int i=0;i<o<<1;i++)
                    res[i]=mul(res[i],dec(1,dec(fln[i],cp[i])));
                res.idft(),res.resize(o);
            }
            res.resize(n);
            return res;
        }

        inline poly pow(int k){
            poly cp=*this;
            assert(cp.size());
            assert(cp.a[0]);
            int c=cp.a[0];
            cp/=c;
            cp=(cp.ln()*k).exp();
            cp*=qpow(c,k);
            return cp;
        }

        inline poly sqrt(){
            int n=size();
            assert(n);
            assert(a[0]==1);
            poly res(1),fiv,cp;
            res[0]=a[0];
            for(int o=2;o<(n<<1);o<<=1){
                cp=a;cp.resize(o);cp.resize(o<<1);
                res.resize(o);fiv=res.inv();fiv.resize(o<<1);
                res.resize(o<<1);
                res.dft(),fiv.dft(),cp.dft();
                for(int i=0;i<o<<1;i++)
                    res[i]=mul(inc(mul(res[i],res[i]),cp[i]),mul((P+1)/2,fiv[i]));
                res.idft(),res.resize(o);
            }
            res.resize(n);
            return res;
        }
        
        inline poly fwt_or(poly a,int op){
            int m=a.size();
            for(int o=2,k=1;k<m;k<<=1,o<<=1)
                for(int i=0;i<m;i+=o)
                    for(int j=0;j<k;j++)
                        op?add(a[i|j|k],a[i|j]):sub(a[i|j|k],a[i|j]);
            return a;
        }
        
        inline poly OR(poly a,poly b){
            int m=a.size();
            a=fwt_or(a,1);b=fwt_or(b,1);
            for(int i=0;i<m;i++)
                a[i]=mul(a[i],b[i]);
            a=fwt_or(a,0);
            return a;
        }
        
        inline void operator|=(poly b){
            poly q=*this;
            *this=OR(*this,b);
        }
        
        inline friend poly operator|(poly a,poly b){
            a|=b;
            return a;
        }
        
        inline poly fwt_and(poly a,int op){
            int m=a.size();
            for(int o=2,k=1;k<m;k<<=1,o<<=1)
                for(int i=0;i<m;i+=o)
                    for(int j=0;j<k;j++)
                        op?add(a[i|j],a[i|j|k]):sub(a[i|j],a[i|j|k]);
            return a;
        }
        
        inline poly AND(poly a,poly b){
            int m=a.size();
            a=fwt_and(a,1);b=fwt_and(b,1);
            for(int i=0;i<m;i++)
                a[i]=mul(a[i],b[i]);
            a=fwt_and(a,0);
            return a;
        }
        
        inline void operator&=(poly b){
            poly q=*this;
            *this=AND(*this,b);
        }
        
        inline friend poly operator&(poly a,poly b){
            a&=b;
            return a;
        }
        
        inline poly fwt_xor(poly a,int op){
            int m=a.size();
            for(int o=2,k=1;k<m;k<<=1,o<<=1)
                for(int i=0;i<m;i+=o)
                    for(int j=0;j<k;j++)
                        if(op){
                            a[i|j]=inc(a[i|j],a[i|j|k]);
                            a[i|j|k]=inc(a[i|j],mul(dec(P,a[i|j|k]),2));
                        }else{
                            a[i|j]=mul(inc(a[i|j],a[i|j|k]),Pi);
                            a[i|j|k]=dec(a[i|j],a[i|j|k]);
                        }
            return a;
        }
        
        inline poly XOR(poly a,poly b){
            int m=a.size();
            a=fwt_xor(a,1);b=fwt_xor(b,1);
            for(int i=0;i<m;i++)
                a[i]=mul(a[i],b[i]);
            a=fwt_xor(a,0);
            return a;
        }
        
        inline void operator^=(poly b){
            poly q=*this;
            *this=XOR(*this,b);
        }
        
        inline friend poly operator^(poly a,poly b){
            a^=b;
            return a;
        }
    };
}

using Poly::init_w;
using Poly::poly;
posted @ 2024-02-16 12:16  QcpyWcpyQ  阅读(9)  评论(0编辑  收藏  举报