zoukankan      html  css  js  c++  java
  • 多项式板子

    FFT

    给定一个(n)次多项式(F(x)),和一个(m)次多项式(G(x)),请求出(F(x))(G(x))的卷积。

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    void read(int &x) {
        char ch; bool ok;
        for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
        for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
    }
    #define rg register
    const int maxn=3e6+1000;
    const double pi=acos(-1);
    int n,m,r[maxn],len;
    struct complex{double x,y;}a[maxn],b[maxn];
    complex operator-(complex a,complex b){return (complex){a.x-b.x,a.y-b.y};}
    complex operator+(complex a,complex b){return (complex){a.x+b.x,a.y+b.y};}
    complex operator*(complex a,complex b){return (complex){a.x*b.x-a.y*b.y,a.x*b.y+b.x*a.y};}
    void fft(complex *a,int f)
    {
        for(rg int i=0;i<n;i++)if(r[i]>i)swap(a[r[i]],a[i]);
        for(rg int i=1;i<n;i<<=1)
        {
            complex wn=(complex){cos(pi/i),f*sin(pi/i)};
            for(rg int j=0;j<n;j+=(i<<1))
            {
                complex w=(complex){1,0};
                for(rg int k=0;k<i;k++)
                {
                    complex x=a[j+k],y=w*a[j+k+i];
                    a[j+k]=x+y,a[j+k+i]=x-y,w=w*wn;
                }
            }
        }
        if(f==-1)for(rg int i=0;i<=m;i++)a[i].x=a[i].x/n+0.1;
    }
    int main()
    {
        read(n),read(m);
        for(rg int i=0,x;i<=n;i++)read(x),a[i].x=x;
        for(rg int i=0,x;i<=m;i++)read(x),b[i].x=x;
        m+=n;for(n=1;n<=m;n<<=1)len++;
        for(rg int i=0;i<n;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(len-1));
        fft(a,1),fft(b,1);
        for(rg int i=0;i<=n;i++)a[i]=a[i]*b[i];
        fft(a,-1);
        for(rg int i=0;i<=m;i++)printf("%d ",(int)a[i].x);
    }
    

    NTT

    给定一个(n)次多项式(F(x)),和一个(m)次多项式(G(x)),请求出(F(x))(G(x))的卷积,并对(998244353)取模。

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    void read(int &x) {
    	char ch; bool ok;
    	for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
    	for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
    }
    #define rg register
    const int maxn=3e6+10,mod=998244353,g=3,ginv=332748118;
    int n,m,a[maxn],b[maxn],len,r[maxn];
    int mi(int a,int b)
    {
    	int ans=1;
    	while(b)
    	{
    		if(b&1)ans=1ll*ans*a%mod;
    		b>>=1,a=1ll*a*a%mod;
    	}
    	return ans;
    }
    void ntt(int *a,int f)
    {
    	for(rg int i=0;i<n;i++)if(r[i]>i)swap(a[r[i]],a[i]);
    	for(rg int i=1;i<n;i<<=1)
    	{
    		int wn=mi(f?g:ginv,(mod-1)/(i<<1));
    		for(rg int j=0;j<n;j+=(i<<1))
    		{
    			int w=1;
    			for(rg int k=0;k<i;k++)
    			{
    				int x=a[j+k],y=1ll*a[j+k+i]*w%mod;
    				a[j+k]=(x+y)%mod,a[j+k+i]=(x-y+mod)%mod,w=1ll*w*wn%mod;
    			}
    		}
    	}
    }
    int main()
    {
    	read(n),read(m);
    	for(rg int i=0;i<=n;i++)read(a[i]);
    	for(rg int i=0;i<=m;i++)read(b[i]);
    	m+=n;for(n=1;n<=m;n<<=1)len++;
    	for(rg int i=0;i<n;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(len-1));
    	ntt(a,1),ntt(b,1);
    	for(rg int i=0;i<n;i++)a[i]=1ll*a[i]*b[i]%mod;
    	ntt(a,0);int inv=mi(n,mod-2);
    	for(rg int i=0;i<=m;i++)printf("%d ",1ll*inv*a[i]%mod);
    }
    

    多项式求逆

    给定一个多项式(F(x)) ,请求出一个多项式(G(x)), 满足(F(x)∗G(x)≡1(mod x^n))。系数对 (998244353)取模。

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    void read(int &x) {
    	char ch; bool ok;
    	for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
    	for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
    }
    #define rg register
    const int maxn=3e6+10,mod=998244353,g=3,ginv=332748118;
    int n,m,a[maxn],b[maxn],c[maxn],r[maxn];
    int mi(int a,int b)
    {
    	int ans=1;
    	while(b)
    	{
    		if(b&1)ans=1ll*ans*a%mod;
    		b>>=1,a=1ll*a*a%mod;
    	}
    	return ans;
    }
    void ntt(int *a,int n,int f)
    {
    	for(rg int i=0;i<n;i++)if(r[i]>i)swap(a[r[i]],a[i]);
    	for(rg int i=1;i<n;i<<=1)
    	{
    		int wn=mi(f?g:ginv,(mod-1)/(i<<1));
    		for(rg int j=0;j<n;j+=(i<<1))
    		{
    			int w=1;
    			for(rg int k=0;k<i;k++)
    			{
    				int x=a[j+k],y=1ll*a[j+k+i]*w%mod;
    				a[j+k]=(x+y)%mod,a[j+k+i]=(x-y+mod)%mod,w=1ll*w*wn%mod;
    			}
    		}
    	}
    	if(f)return ;
    	int inv=mi(n,mod-2);
    	for(rg int i=0;i<n;i++)a[i]=1ll*a[i]*inv%mod;
    }
    void solve(int n,int *a,int *b)
    {
    	if(n==1){b[0]=mi(a[0],mod-2);return ;}
    	solve((n+1)>>1,a,b);int m,len=0;
    	for(m=1;m<=n*2;m<<=1)len++;
    	for(rg int i=0;i<n;i++)c[i]=a[i];
    	for(rg int i=n;i<m;i++)c[i]=0;
    	for(rg int i=0;i<m;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(len-1));
    	ntt(b,m,1),ntt(c,m,1);
    	for(rg int i=0;i<m;i++)b[i]=((2ll*b[i]-1ll*c[i]*b[i]%mod*b[i]%mod)+mod)%mod;
    	ntt(b,m,0);
    	for(rg int i=n;i<m;i++)b[i]=0;
    }
    int main()
    {
    	read(n);
    	for(rg int i=0;i<n;i++)read(a[i]);
    	solve(n,a,b);
    	for(rg int i=0;i<n;i++)printf("%d ",b[i]);
    }
    

    多项式求导

    其实就是幂函数的求导

    [f(x)=sum_{i=0}a_ix_i\ f'(x)=sum_{i=1}a_{i}x^{i-1} ]

    多项式求ln

    给出(n-1)次多项式(A(x)),求一个 (mod{:x^n})下的多项式(B(x)),满足(B(x)equiv ln A(x)).
    ( ext{mod } 998244353)下进行,且(a_iin [0, 998244353] cap mathbb{Z})
    代码:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    void read(int &x) {
    	char ch; bool ok;
    	for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
    	for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
    }
    #define rg register
    const int maxn=8e5+10,mod=998244353,g=3,gi=332748118;
    int n,m,a[maxn],b[maxn],c[maxn],len,r[maxn],d[maxn],e[maxn];
    int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
    int del(int x,int y){return x-y<0?x-y+mod:x-y;}
    int mul(int x,int y){return 1ll*x*y-1ll*x*y/mod*mod;}
    int mi(int a,int b)
    {
    	int ans=1;
    	while(b)
    	{
    		if(b&1)ans=mul(a,ans);
    		b>>=1,a=mul(a,a);
    	}
    	return ans;
    }
    void ntt(int *a,int n,int f)
    {
    	for(rg int i=0;i<n;i++)if(r[i]>i)swap(a[i],a[r[i]]);
    	for(rg int i=1;i<n;i<<=1)
    	{
    		int wn=mi((f?g:gi),(mod-1)/(i<<1));
    		for(rg int j=0;j<n;j+=(i<<1))
    		{
    			int w=1;
    			for(rg int k=0;k<i;k++)
    			{
    				int x=a[j+k],y=mul(a[j+k+i],w);
    				a[j+k]=add(x,y),a[j+k+i]=del(x,y),w=mul(w,wn);
    			}
    		}
    	}
    	if(f)return ;int inv=mi(n,mod-2);
    	for(rg int i=0;i<n;i++)a[i]=mul(a[i],inv);
    }
    void solve(int n,int *a,int *b)
    {
    	if(n==1){b[0]=mi(a[0],mod-2);return ;}
    	solve((n+1)>>1,a,b);len=0;
    	for(m=1;m<=n*2;m<<=1)len++;
    	for(rg int i=0;i<n;i++)c[i]=a[i];
    	for(rg int i=n;i<m;i++)c[i]=0;
    	for(rg int i=0;i<m;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(len-1));
    	ntt(c,m,1),ntt(b,m,1);
    	for(rg int i=0;i<m;i++)b[i]=del(mul(2,b[i]),mul(mul(b[i],b[i]),c[i]));
    	ntt(b,m,0);
    	for(rg int i=n;i<m;i++)b[i]=0;
    }
    void getln(int *a,int n)
    {
    	solve(n,a,b);len=0;
    	for(rg int i=1;i<n;i++)d[i-1]=mul(a[i],i);
    	for(m=1;m<=n;m<<=1)len++;
    	for(rg int i=0;i<m;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(len-1));
    	ntt(d,m,1),ntt(b,m,1);
    	for(rg int i=0;i<m;i++)d[i]=mul(d[i],b[i]);
    	ntt(d,m,0);e[0]=0;
    	for(rg int i=1;i<m;i++)e[i]=mul(d[i-1],mi(i,mod-2));
    }
    int main()
    {
    	read(n);
    	for(rg int i=0;i<n;i++)read(a[i]);
    	for(m=1;m<=n;m<<=1);getln(a,m);
    	for(rg int i=0;i<n;i++)printf("%d ",e[i]);
    }
    

    多项式求exp

    给出(n-1)次多项式(A(x)),求一个(mod x^n)下的多项式(B(x)),满足(B(x)≡e^A(x)).
    代码:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    void read(int &x) {
    	char ch; bool ok;
    	for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
    	for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
    }
    #define rg register
    const int maxn=8e5+10,mod=998244353,g=3,gi=332748118;
    int n,a[maxn],r[maxn],c[maxn],f[maxn],b[maxn],s[maxn],w[maxn],h[maxn];
    int mul(int x,int y){return 1ll*x*y-1ll*x*y/mod*mod;}
    int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
    int del(int x,int y){return x-y<0?x-y+mod:x-y;}
    int mi(int a,int b){
    	int ans=1;
    	while(b){
    		if(b&1)ans=mul(ans,a);
    		b>>=1,a=mul(a,a);
    	}
    	return ans;
    }
    void ntt(int *a,int n,int f){
    	for(rg int i=0;i<n;i++)if(r[i]>i)swap(a[i],a[r[i]]);
    	for(rg int i=1;i<n;i<<=1){
    		int wn=mi(f?g:gi,(mod-1)/(i<<1));
    		for(rg int j=0;j<n;j+=(i<<1)){
    			int w=1;
    			for(rg int k=0;k<i;k++){
    				int x=a[j+k],y=mul(w,a[j+k+i]);
    				a[j+k]=add(x,y),a[j+k+i]=del(x,y),w=mul(w,wn); 
    			}
    		}
    	}
    	if(f)return ;int inv=mi(n,mod-2);
    	for(rg int i=0;i<n;i++)a[i]=mul(a[i],inv); 
    }
    void get_inv(int *a,int *b,int n){
    	if(n==1)return b[0]=mi(a[0],mod-2),void();
    	get_inv(a,b,(n+1)>>1);
    	int m,len=0;
    	for(m=1;m<=n<<1;m<<=1)len++;
    	for(rg int i=0;i<m;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(len-1));
    	for(rg int i=0;i<n;i++)c[i]=a[i];
    	for(rg int i=n;i<m;i++)c[i]=0;
    	ntt(c,m,1),ntt(b,m,1);
    	for(rg int i=0;i<m;i++)
    		b[i]=del(mul(2,b[i]),mul(c[i],mul(b[i],b[i])));
    	ntt(b,m,0);
    	for(rg int i=n;i<m;i++)b[i]=0;
    }
    void get_ln(int *a,int *b,int n){
    	for(rg int i=0;i<n;i++)w[i]=mul(a[i+1],i+1);
    	get_inv(a,h,n);int m,len=0;
    	for(m=1;m<=n<<1;m<<=1)len++;
    	for(rg int i=0;i<m;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(len-1));
    	ntt(w,m,1),ntt(h,m,1);
    	for(rg int i=0;i<m;i++)w[i]=mul(w[i],h[i]);
    	ntt(w,m,0);b[0]=0;
    	for(rg int i=0;i<m;i++)b[i+1]=mul(w[i],mi(i+1,mod-2)),h[i]=0;
    	for(rg int i=n;i<m;i++)b[i]=0;
    }
    void get_exp(int *a,int *b,int n){
    	if(n==1)return b[0]=1,void();
    	get_exp(a,b,(n+1)>>1);
    	get_ln(b,s,n);
    	int m,len=0;
    	for(m=1;m<=n<<1;m<<=1)len++;
    	for(rg int i=0;i<m;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(len-1));
    	for(rg int i=n;i<m;i++)s[i]=0;
    	for(rg int i=0;i<n;i++)s[i]=del(a[i],s[i]);s[0]=add(s[0],1);
    	ntt(s,m,1),ntt(b,m,1);
    	for(rg int i=0;i<m;i++)b[i]=mul(b[i],s[i]);
    	ntt(b,m,0);
    	for(rg int i=n;i<m;i++)b[i]=0;
    }
    int main()
    {
    	read(n);
    	for(rg int i=0;i<n;i++)read(a[i]);
    	get_exp(a,f,n);
    	for(rg int i=0;i<n;i++)printf("%d ",f[i]);
    }
    

    多项式快速幂

    给定一个(n-1)次多项式(A(x)),求一个在(mod x^n)意义下的多项式(B(x)),使(B(x)≡A^k(x) (mod x^n))
    代码:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    void read(int &x) {
    	char ch; bool ok;
    	for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
    	for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
    }
    #define rg register
    const int maxn=8e5+10,mod=998244353,g=3,gi=332748118;
    char ch[maxn];
    int n,m,tot,k,now=1,r[maxn],a[maxn],b[maxn],w[maxn],h[maxn],d[maxn],c[maxn],f[maxn],s[maxn];
    int mul(int x,int y){return 1ll*x*y-1ll*x*y/mod*mod;}
    int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
    int del(int x,int y){return x-y<0?x-y+mod:x-y;}
    int mi(int a,int b){
    	int ans=1;
    	while(b){
    		if(b&1)ans=mul(ans,a);
    		b>>=1,a=mul(a,a);
    	}
    	return ans;
    }
    void ntt(int *a,int n,int f){
    	for(rg int i=0;i<n;i++)if(r[i]>i)swap(a[i],a[r[i]]);
    	for(rg int i=1;i<n;i<<=1){
    		int wn=mi(f?g:gi,(mod-1)/(i<<1));
    		for(rg int j=0;j<n;j+=i<<1){
    			int w=1;
    			for(rg int k=0;k<i;k++){
    				int x=a[j+k],y=mul(w,a[j+k+i]);
    				a[j+k]=add(x,y),a[j+k+i]=del(x,y),w=mul(w,wn);
    			}
    		}
    	}
    	if(f)return ;int inv=mi(n,mod-2);
    	for(rg int i=0;i<n;i++)a[i]=mul(a[i],inv);
    }
    void get_inv(int *a,int *b,int n){
    	if(n==1)return b[0]=mi(a[0],mod-2),void(); 
    	get_inv(a,b,(n+1)>>1);int m,len=0;for(m=1;m<=n<<1;m<<=1)len++;
    	for(rg int i=0;i<m;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(len-1));
    	for(rg int i=0;i<n;i++)c[i]=a[i];
    	for(rg int i=n;i<m;i++)c[i]=0;
    	ntt(c,m,1),ntt(b,m,1);
    	for(rg int i=0;i<m;i++)b[i]=del(mul(2,b[i]),mul(c[i],mul(b[i],b[i])));
    	ntt(b,m,0);
    	for(rg int i=n;i<m;i++)b[i]=0;
    }
    void get_ln(int *a,int *b,int n){
    	for(rg int i=0;i<n;i++)w[i]=mul(a[i+1],i+1);
    	get_inv(a,h,n);int m,len=0;for(m=1;m<=n<<1;m<<=1)len++;
    	for(rg int i=0;i<m;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(len-1));
    	ntt(h,m,1),ntt(w,m,1);
    	for(rg int i=0;i<m;i++)w[i]=mul(w[i],h[i]);
    	ntt(w,m,0);b[0]=0;
    	for(rg int i=0;i<m;i++)b[i+1]=mul(w[i],mi(i+1,mod-2)),h[i]=w[i]=0;
    	for(rg int i=n;i<m;i++)b[i]=0; 
    }
    void get_exp(int *a,int *b,int n){
    	if(n==1)return b[0]=1,void();
    	get_exp(a,b,(n+1)>>1),get_ln(b,s,n);
    	int m,len=0;for(m=1;m<=n<<1;m<<=1)len++;
    	for(rg int i=0;i<m;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(len-1));
    	for(rg int i=0;i<n;i++)s[i]=del(a[i],s[i]);s[0]=add(s[0],1);
    	ntt(s,m,1),ntt(b,m,1);
    	for(rg int i=0;i<m;i++)b[i]=mul(b[i],s[i]);
    	ntt(b,m,0);
    	for(rg int i=n;i<m;i++)b[i]=0;
    }
    int main()
    {
    	read(n),read(k);
    	for(rg int i=0;i<n;i++)read(a[i]);
    	get_ln(a,d,n);for(rg int i=0;i<n;i++)d[i]=mul(k,d[i]);
    	get_exp(d,f,n);for(rg int i=0;i<n;i++)printf("%d ",f[i]);
    }
    
  • 相关阅读:
    scipy.spatial.distance.cdist
    关于hstack和Svstack
    numpy.hstack(tup)
    numpy.random.uniform(记住文档网址)
    Python集合(set)类型的操作
    python+Eclipse+pydev环境搭建
    python数据挖掘领域工具包
    LVS 命令使用
    CMD mysql 备份脚本
    Windos Server Tomcat 双开配置
  • 原文地址:https://www.cnblogs.com/lcxer/p/10628507.html
Copyright © 2011-2022 走看看