• 【洛谷5205】【模板】多项式开根


    点此看题面

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

    前言

    在知道多项式乘法逆的前提下,这道题的推导其实是非常简单,甚至要简单于多项式乘法逆的。

    但由于多项式开根最后的求解依然需要用到多项式乘法逆,所以总体难度还是高于多项式乘法逆的?

    推式子

    按照多项式乘法逆的套路,我们可以递归求解此题。

    对于边界,显然当递归到(n=0)的时候,由于题目保证(a_0=1),所以(b_0=1)

    (话说如果(a_0)不等于(1),那么可能会有多个(b_0)满足(b_0^2equiv1),我也很想知道这样子该怎么去做)

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

    [H(x)^2equiv F(x)(mod x^{lfloorfrac n2 floor}) ]

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

    [G(x)^2equiv F(x)(mod x^{lfloorfrac n2 floor}) ]

    则,显然就可以得到:

    [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) ]

    然后,由于(G(x)^2equiv F(x)(mod x^n)),所以:

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

    此时只要通过移项就可以得到:

    [G(x)equivfrac{F(x)+H(x)^2}{2H(x)}(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
    using namespace std;
    int n,a[N+5],b[N<<2];
    I int QP(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;}
    class Poly
    {
    	private:
    		int P,L,R[N<<2],t[N<<2],k[N<<2],PR,IPR,I2;
    		I void T(int *s,CI p)//NTT
    		{
    			RI i,j,k,U,S,x,y;for(i=0;i^P;++i) i<R[i]&&(x=s[i],s[i]=s[R[i]],s[R[i]]=x);
    			for(i=1;i^P;i<<=1) for(U=QP(p,(X-1)/(i<<1)),j=0;j^P;j+=i<<1) for(S=1,k=0;k^i;
    				S=1LL*S*U%X,++k) 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() {PR=3,IPR=QP(3,X-2),I2=X+1>>1;}
    		I void Inv(CI n,int *a,int *b)//多项式乘法逆
    		{
    			if(!n) return (void)(b[0]=QP(a[0],X-2));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];W(i^P) t[i++]=0;
    			for(T(b,PR),T(t,PR),i=0;i^P;++i) b[i]=(2LL*b[i]-1LL*t[i]*b[i]%X*b[i]%X+X)%X;
    			RI t=QP(P,X-2);for(T(b,IPR),i=0;i<=n;++i) b[i]=1LL*b[i]*t%X;W(i^P) b[i++]=0;
    		}
    		I void Sqrt(CI n,int *a,int *b)//多项式开根
    		{
    			if(!n) return (void)(b[0]=1);Sqrt(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^P;++i) k[i]=0;for(Inv(n,b,k),i=0;i<=n;++i) t[i]=a[i];W(i^P) t[i++]=0;
    			for(T(t,PR),T(b,PR),T(k,PR),i=0;i^P;++i) b[i]=(1LL*b[i]*b[i]+t[i])%X*k[i]%X*I2%X;//计算新多项式
    			RI t=QP(P,X-2);for(T(b,IPR),i=0;i<=n;++i) b[i]=1LL*b[i]*t%X;W(i^P) b[i++]=0;//注意清空
    		}
    }P;
    int main()
    {
    	RI i;for(scanf("%d",&n),--n,i=0;i<=n;++i) scanf("%d",a+i);
    	for(P.Sqrt(n,a,b),i=0;i<=n;++i) printf("%d%c",b[i]," 
    "[i==n]);return 0;
    }
    
  • 相关阅读:
    Android底部菜单栏的两种实现方式 附完整源码
    如何创建WebView
    实现 unity MonoBehaviour API5.4 的消息
    linux常用命令2
    Mac 自带的Apache php 狼神的
    高频sql语句汇总。不断更新。。
    4.数据库mysql相关
    Android keystore文件查看应用签名md5
    Java 多线程进阶-并发协作控制
    Java 多线程进阶-并发数据结构
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/PolySqrt.html
Copyright © 2020-2023  润新知