• 【洛谷4238】【模板】多项式乘法逆


    点此看题面

    大致题意: 给定多项式(F(x)),求(G(x))满足(F(x)*G(x)equiv1(mod x^n)),向(998244353)取模。

    前言

    板子题只会抄题解......

    不得不说,虽然这个思路很难想到,但看完题解还是很好理解的。

    推式子

    我们可以递归求解此题。

    对于边界,显然当递归到(n=0)的时候,可直接求出(G(x))(0)次项(即常数项)的系数就是(F(x))(0)次项系数的逆元。

    否则,假设我们当前已知:

    [F(x)*H(x)equiv1(mod x^{lfloorfrac n2 floor}) ]

    由于(F(x)*G(x)equiv1(mod x^n)),所以显然可知

    [F(x)*G(x)equiv1(mod x^{lfloorfrac n2 floor}) ]

    则,若我们将两式相减,就可以得到:

    [F(x)*(G(x)-H(x))equiv0(mod x^{lfloorfrac n2 floor}) ]

    (F(x))去掉,就得到:

    [G(x)-H(x)equiv0(mod x^{lfloorfrac n2 floor}) ]

    考虑我们现在要求出一个多项式,满足与(F(x))卷积模(x^n)(1)

    则显然,我们必须要想办法,让此处的模数由(x^{lfloorfrac n2 floor})变为(x^n)

    怎么办呢?将式子两边同时平方便可。即:

    [(G(x)-H(x))^2equiv0(mod x^n) ]

    用完全平方公式拆平方:

    [G(x)^2-2G(x)*H(x)+H(x)^2equiv0(mod x^n) ]

    然后,此时我们再把(F(x))卷积上去,就得到:

    [F(x)*G(x)^2-2F(x)*G(x)*H(x)+F(x)*H(x)^2equiv0(mod x^n) ]

    由于(F(x)*G(x)equiv1(mod x^n)),所以我们就可以进一步化简得到:

    [G(x)-2H(x)+F(x)*H(x)^2equiv0(mod x^n) ]

    此时我们便可以发现,式子中(G(x))已经被独立出来了,因此只要通过移项就可以得到:

    [G(x)equiv2H(x)-F(x)*H(x)^2(mod x^n) ]

    关于这个式子,只要用(NTT)做多项式乘法就可以了。

    注意在具体实现中,(G(x))(H(x))完全可以存在一个数组中。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 100000
    #define X 998244353
    #define Qinv(x) Qpow(x,X-2)
    #define swap(x,y) (x^=y^=x^=y)
    using namespace std;
    int n,a[N+5],b[4*N+5];
    class FastIO
    {
    	private:
    		#define FS 100000
    		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
    		#define pc(c) (C==E&&(clear(),0),*C++=c)
    		#define tn (x<<3)+(x<<1)
    		#define D isdigit(c=tc())
    		int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
    	public:
    		I FastIO() {A=B=FI,C=FO,E=FO+FS;}
    		Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
    		Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
    		Tp I void write(Con Ty& x,Con char& y) {write(x),pc(y);}
    		I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
    }F;
    I int Qpow(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
    template<int SZ,int PR> class Poly
    {
    	private:
    		int IPR,P,L,R[4*N+5],t[4*N+5];
    		I void T(int *s,CI op)
    		{
    			RI i,j,k,U,S,x,y;for(i=0;i^P;++i) i<R[i]&&swap(s[i],s[R[i]]);
    			for(i=1;i^P;i<<=1) for(U=Qpow(~op?PR:IPR,(X-1)/(i<<1)),j=0;j^P;j+=i<<1)
    				for(S=1,k=0;k^i;++k,S=1LL*S*U%X) s[j+k]=((x=s[j+k])+(y=1LL*S*s[i+j+k]%X))%X,s[i+j+k]=(x-y+X)%X;
    		}
    	public:
    		I Poly() {IPR=Qinv(PR);}
    		I void Inv(CI n,int *a,int *b)
    		{
    			if(!n) return (void)(b[0]=Qinv(a[0]));Inv(n>>1,a,b);//处理边界,不在边界则继续递归
    			RI i;P=1,L=0;W(P<=(n<<1)) P<<=1,++L;for(i=0;i^P;++i) R[i]=(R[i>>1]>>1)|((i&1)<<L-1);//预处理
    			for(i=0;i<=n;++i) t[i]=a[i];T(b,1),T(t,1);//NTT
    			for(i=0;i^P;++i) b[i]=(2LL*b[i]%X-1LL*t[i]*b[i]%X*b[i]%X+X)%X;T(b,-1);//计算新多项式
    			RI t=Qinv(P);for(i=0;i<=n;++i) b[i]=1LL*b[i]*t%X;for(i=n+1;i^P;++i) b[i]=0;//注意将高位清空,否则会影响后续操作
    		}
    };Poly<N,3> P;
    int main()
    {
    	RI i;for(F.read(n),--n,i=0;i<=n;++i) F.read(a[i]);//读入
    	for(P.Inv(n,a,b),i=0;i<=n;++i) F.write(b[i]," 
    "[i==n]);return F.clear(),0;//输出
    }
    
  • 相关阅读:
    Docker部署Tomcat
    Docker部署MySQL
    kettle 共享数据库连接(解决每次都需要创建数据库连接问题)
    Kettle8.2的安装与使用
    Kettle 使用JS脚本 增加UUID输出列
    kettle使用(mysql导入MongoDB)
    Eclipse从Git上下载代码
    Eclipse中使用git
    在windows下安装git中文版客户端并连接gitlab
    eclipse中git的安装、配置和使用
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/PolyInv.html
Copyright © 2020-2023  润新知