多项式的一些操作

大多数东西只有代码啦
主要是因为数学公式太烦了
代码中\(vc\)指的是\(vector<int>\)
树套树每套一层多一个\(log\)
多项式每套一层不多\(log\).
\(nlog^2n\)的树套树能跑\(2*10^5\),\(nlogn\)的多项式多套几层只能跑\(10^5\)
所以log越多越快
细思极恐


快速傅里叶变换 FFT

经过一番精妙的数学推导得出的

void FFT(Complex *a,int tp){
    for(int i=0;i<Lim;i++)
    if(i<rev[i])swap(a[i],a[rev[i]]);
    for(int pos=1;pos<Lim;pos<<=1){
        Complex w; w.a=cos(pi/pos),w.b=tp*sin(pi/pos);
        for(int R=pos<<1,j=0;j<Lim;j+=R){
            Complex p; p.a=1,p.b=0;
            for(int k=j;k<pos+j;k++,p=p*w){
                Complex x=a[k],y=p*a[k+pos];
                a[k]=x+y,a[k+pos]=x-y;
            }
        }
    }
}

快速数论变换 NTT
void NTT(LL *a,int tp){
    for(int i=0;i<Lim;i++)
    if(i<rev[i])swap(a[i],a[rev[i]]);
    for(int pos=1;pos<Lim;pos<<=1){
        LL w=ksm(3,(P-1)/(pos<<1));
        if(tp==-1)w=ksm(w,P-2);
        for(int R=pos<<1,j=0;j<Lim;j+=R){
            LL p=1;
            for(int k=j;k<j+pos;p=(p*w)%P,k++){
                LL x=a[k],y=(p*a[k+pos])%P;
                a[k]=(x+y)%P,a[k+pos]=(x-y+P)%P;
            }
        }
    }
    if(tp==-1)
    for(int i=0;i<Lim;i++)a[i]=(a[i]*inv)%P;
}

快速沃尔什变换 FWT

\(OR\)卷积
这个其实是\(FMT\)

void FWT_or(LL *a,int tp){
    for(int i=1;i<Lim;i<<=1)
    for(int R=i<<1,j=0;j<Lim;j+=R)
    for(int k=j;k<j+i;k++)
    (a[k+i]+=a[k]*(LL)tp+P)%=P;
}

\(AND\)卷积
江道理应该把每一位反过来然后做\(FMT\)

void FWT_and(LL *a,int tp){
    for(int i=1;i<Lim;i<<=1)
    for(int R=i<<1,j=0;j<Lim;j+=R)
    for(int k=j;k<j+i;k++)
    (a[k]+=a[k+i]*(LL)tp+P)%=P;
}

\(XOR\)卷积
\(This~is~true~FWT!\)

void FWT_xor(LL *a,int tp){
    for(int i=1;i<Lim;i<<=1)
    for(int R=i<<1,j=0;j<Lim;j+=R)
    for(int k=j;k<j+i;k++){
        LL x=a[k],y=a[k+i];
        a[k]=(x+y)%P,a[k+i]=(x-y+P)%P;
        if(tp==-1)(a[k]=a[k]*inv2%P),(a[k+i]=a[k+i]*inv2%P);
    }
}

快速莫比乌斯变换 FMT

本质是高维前缀和

void FMT(int *a){
    for(int i=0;i<Lim;i++)
    for(int j=0;j<n;j++)
    if(j>>i&1)a[j]=(a[j]+a[j^(1<<i)])%P;
}

多项式求逆

直接倍增就好了

void solve(){
    bin[0]=n;
    for(cnt=1;;cnt++){
        bin[cnt]=(bin[cnt-1]+1)/2;
        if(bin[cnt]==1)break;
    }
    g[0]=ksm(f[0],P-2),NTT(f,1);
    for(rg i=cnt-1;~i;i--){
        for(rg j=bin[i+1];j<Lim;j++)g[j]=0;
        for(rg j=0;j<bin[i+1];j++){
            h[j]=(g[j]<<1);
            if(h[j]>P)h[j]-=P;
        }
        NTT(g,1);
        for(rg j=0;j<Lim;j++)
        g[j]=(g[j]*g[j]%P*f[j])%P;
        NTT(g,-1);
        for(rg j=0;j<bin[i];j++)
        g[j]=(h[j]-g[j]+P)%P;
    }
}

多项式微分
void diff(vc &a){
    int len=a.size()-1;
    for(int i=0;i<len-1;i++)a[i]=1ll*a[i+1]*(i+1)%P;
    a[len]=0,a.resize(len);
}
多项式积分
void inte(vc &a){
    int len=a.size();
    a.resize(len+1);
    for(int i=len;i;i--)
    a[i]=1ll*a[i-1]*ksm(i,P-2)%P;
    a[0]=0;
}

这两个是基本操作


多项式求\(ln\)

牛顿迭代就行了.

vc getln(vc a,int n){
    vc g=getinv(a,n);
    diff(a);
    mul(g,a),inte(g);
    return g;
}

多项式\(exp\)

常数巨大还在卡常
如果你那么想看代码板子里有.


板子

这里默认对998244353取模
即拉即用造福社会

namespace poly{
    typedef vector<int> vc; vc h; 
    int mi[41],iv[41],bin[41],inv,len,Lim,rev[N],cnt;
    int ksm(int a,int p){
        int res=1;
        while(p){
            if(p&1)res=1ll*res*a%P;
            a=1ll*a*a%P,p>>=1;
        }
        return res;
    }
    void init(){
        for(int i=0;(1<<i)<=P-1;i++)mi[i]=ksm(3,(P-1)/(1<<i)),iv[i]=ksm(mi[i],P-2);
    }
    void init_p(int S){
        len=0;
        for(Lim=1;Lim<=S;Lim<<=1)len++; inv=ksm(Lim,P-2);
        for(int i=0;i<Lim;i++)
        rev[i]=(rev[i>>1]>>1)|((i&1)<<(len-1));
    }
    void NTT(vc &a,int tp){
        a.resize(Lim);
        for(rg i=0;i<Lim;i++)
        if(i<rev[i])swap(a[i],a[rev[i]]); 
        for(rg pos=1,s=1;pos<Lim;pos<<=1,s++){
            int w=(tp==1)?mi[s]:iv[s];
            for(rg R=pos<<1,j=0;j<Lim;j+=R){
                int p=1;
                for(rg k=j;k<j+pos;p=1ll*p*w%P,k++){
                    int x=a[k],y=1ll*p*a[k+pos]%P;
                    a[k]=(x+y)%P,a[k+pos]=(x-y+P)%P;
                }
            }
        } 
        if(tp==-1)
        for(int i=0;i<Lim;i++)a[i]=(1ll*a[i]*inv)%P;
    }
    void mul(vc &a,vc b){
        init_p(a.size()+b.size()+1);
        a.resize(Lim),b.resize(Lim);
        NTT(a,1),NTT(b,1);
        for(int i=0;i<Lim;i++)a[i]=1ll*a[i]*b[i]%P;
        NTT(a,-1);
    }
    void mul2(vc &a,vc b){
        init_p(2*a.size()+b.size()+1);
        NTT(a,1),NTT(b,1);
        for(int i=0;i<Lim;i++)a[i]=1ll*a[i]*a[i]%P*b[i]%P;
        NTT(a,-1);
    }
    vc getinv(vc f,int n){
        bin[0]=n;
        for(cnt=1;;cnt++){
            bin[cnt]=(bin[cnt-1]+1)/2;
            if(bin[cnt]==1)break;
        }
        vc tmp,g; g.resize(1);
        g[0]=ksm(f[0],P-2); 
        for(rg i=cnt-1;~i;i--){
            h.resize(bin[i]);
            for(rg j=0;j<bin[i+1];j++){
                h[j]=(g[j]<<1);
                if(h[j]>P)h[j]-=P;
            }
            tmp.resize(bin[i]);
            for(rg j=0;j<bin[i];j++)tmp[j]=f[j];
            mul2(g,tmp),g.resize(bin[i]);
            for(rg j=0;j<bin[i];j++)
            g[j]=(h[j]-g[j]+P)%P;
        }
        return g;
    }
    void diff(vc &a){
        int len=a.size()-1;
        for(int i=0;i<len-1;i++)a[i]=1ll*a[i+1]*(i+1)%P;
        a[len]=0,a.resize(len);
    }
    void inte(vc &a){
        int len=a.size();
        a.resize(len+1);
        for(int i=len;i;i--)
        a[i]=1ll*a[i-1]*ksm(i,P-2)%P;
        a[0]=0;
    }
    vc getln(vc a,int n){
        a.resize(n+1);
        vc g=getinv(a,n);
        diff(a);
        mul(g,a),inte(g);
        g.resize(n+1);
        return g;
    }
    vc getexp(vc f,int n){
        int bn[41],cnt=0;
        bn[0]=n*2;
        for(cnt=1;;cnt++){
            bn[cnt]=(bn[cnt-1]-1)/2+1;
            if(bn[cnt]==1)break;
        }
        vc g; g.resize(1),g[0]=1;
        for(int i=cnt-1;~i;i--){
            vc tmp=getln(g,bn[i]);
            for(int j=0;j<bn[i];j++)
            tmp[j]=((f[j]-tmp[j])%P+P)%P;
            tmp[0]=(tmp[0]+1)%P;
            mul(g,tmp);
            g.resize(bn[i]);
        }
        return g;
    }
}

转载于:https://www.cnblogs.com/Romeolong/p/10044268.html

为了方便,把代码放在Word里面了,每次上机实验的题目代码都在。 第一次: 对如下多项式编写类定义: + + +…+ 其中,n为多项式的次数。完成如下功能: (1) 可存储任意大的多项式(提示:可用动态数组实现)。 (2) 定义构造函数、析构函数、拷贝构造函数。 (3) 包含一个static成员存储定义的多项式的数量。 (4) 定义一个成员函数输出多项式。(可参照-x^4-6x^3+5格式输出) (5) 定义一个成员函数计算多项式的值。 (6) 写main函数测试类的功能。 (7) 采用多文件实现。 考虑:哪些成员函数可以声明为const. 第二次: (8) 重载“+”运算符,实现两个多项式相加。 (9) 重载“-”运算符,实现两个多项式相减。 (10) 重载“*”运算符,实现两个多项式相乘。 (11) 重载“=”运算符,实现两个多项式的赋值运算。 考虑:把其中某个运算符重载为友元函数。 第三次: C++的一般编译器都定义和封装了字符串功能,请模仿定义string类的实现,可以实现并支持如下功能: (1)string s = “吉林大学”; (2)string t = s; (3)string m; m = t; (4)m.legnth() 函数测量字符串的长度 (5)m.cat(string const &)连接字符串 第四次: 我公司为仪器生产企业,目前生产摄像机和行车记录仪两种产品,分别销售给用户。 摄像机包含摄像、图像质量设定、编码算法等属性。 将摄像机增加相应芯片(具有操作菜单、自动拍摄、车速传感器、源代码等功能)后,形成一个行车记录仪。 要求: 设计摄像机类,并请根据下列不同的功能要求,采用不同的继承方式,设计行车记录仪类,并添加测试代码,体验不同继承方式下的成员访问属性。(类设计时可根据需要自行添加数据成员和其他成员函数。) (1) 行车记录仪的芯片可以使用摄像机的摄像、图像质量设定功能。 行车记录仪用户可以操作行车记录仪的操作菜单和摄像机的摄像功能。 (2)行车记录仪的芯片可以使用摄像机的拍摄、图像质量设定功能。 行车记录仪用户仅仅可以操作行车记录仪的操作菜单。 (3) 行车记录仪的芯片可以使用摄像机的拍摄、图像质量设定功能。 行车记录仪用户仅仅可以操作行车记录仪的操作菜单 同时其他公司购买行车记录仪,因该公司也用于销售,不得泄露其全部内容 课后: (1)采用组合方式设计行车记录仪类,增加相应测试代码,体验继承和组合的关系。 (2)分别为继承和组合方式下为各类添加构造函数、析构函数,增加相应测试代码,体验对象的初始化和构造顺序。 (3)将摄像机类和行车记录仪类功能相近的函数(如拍摄、编码等功能函数)设为同名函数,增加相应测试代码,体验同名函数覆盖。 (4)为我公司建立一个多态的产品类层次结构,使用抽象类,测试时,创建一个基类指针的容器,通过基类指针调用虚函数,体验多态。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值