多项式开根

对于要开根的H(x),求出开根后的G(x)

推导过程如下,对于\tiny x^{\left \lceil \frac{n}{2} \right \rceil}以下简称k

\tiny F(x)\equiv G(x)^2 (mod\, x^n)

\tiny H(x)^2\equiv F(x)(mod\, k)

\tiny G(x)^2\equiv F(x)(mod\,k)

\tiny H(x)\equiv G(x) (mod\, k)

\tiny H(x) -G(x)\equiv 0 (mod\,k)

\tiny H(x)^2+G(x)^2-2H(x)G(x)\equiv 0 (mod\, x^n)

要求的是G(X)

\tiny F(x)\equiv G(x)^2 (mod\, x^n)

 \tiny [ H(x)^2+F(x)\, ] /2H(x)\equiv G(x) (mod\, x^n)

故我们要求出H(x)的逆元,2的逆元

# include<iostream>
using namespace std;
# define G 3
# define MAXN 262145
# define mod 998244353
# define inv 499122177
typedef long long int  ll;

ll A[MAXN],B[MAXN],rev[MAXN],tp[MAXN],tq[MAXN],ta[MAXN],tb[MAXN];


void init(int k)
{
    int len=(1<<k);

    for(int i=0;i<len;i++)
    {
        rev[i]=0;
    }
    for(int i=0;i<len;i++)
    {
        rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));
    }
    return ;

}

ll qp(ll base,ll pow)
{
    ll ans=1;

    while(pow)
    {
        if(pow&1)
        {
            ans=ans*base%mod;
        }

        pow>>=1;

        base=base*base%mod;

    }
    return ans;

}

void NTT(ll *a,int n,int flag)
{

    for(int i=0;i<n;i++)
    {
        if(i<rev[i])
        {
            swap(a[i],a[rev[i]]);

        }
    }

    for(int h=1;h<n;h<<=1)
    {
        ll gn=qp(G,(mod-1)/(h<<1));

        if(flag==-1)
        {
            gn=qp(gn,mod-2);

        }
        for(int j=0;j<n;j+=2*h)
        {

            ll g=1;

            for(int k=j;k<j+h;k++)
            {
                ll x=a[k];
                ll y=a[k+h]*g%mod;

                a[k]=(x+y)%mod;

                a[k+h]=((x-y)%mod+mod)%mod;

                g=gn*g%mod;

            }
        }
    }

    if(flag==-1)
    {
        ll invn=qp(n,mod-2);

        for(int i=0;i<n;i++)
        {

            a[i]=a[i]*invn%mod;

        }
    }
    return ;

}
void mul(ll *a,ll*b,ll*c,int n,int m)
{

    int k=1,s=2;

    while((1<<k)<n+m-1)
    {
        k++;
        s<<=1;

    }
    init(k);


    for(int i=0;i<n;i++)
    {
        tp[i]=a[i];
    }
    for(int i=n;i<s;i++)
    {
        tp[i]=0;
    }
    NTT(tp,s,1);

    for(int i=0;i<m;i++)
    {
        tq[i]=b[i];
    }

    for(int i=m;i<s;i++)
    {
        tq[i]=0;
    }

    NTT(tq,s,1);

    for(int i=0;i<s;i++)
    {
        c[i]=tp[i]*tq[i]%mod;

    }

    NTT(c,s,-1);

}

void getinv(ll *a,ll *b,int n)
{
    if(n==1)
    {
        b[0]=qp(a[0],mod-2);
        return ;

    }
    getinv(a,b,(n+1)>>1);

    int k=1,s=2;

    while((1<<k)<n+n-1)
    {
        k++;
        s<<=1;
    }
    init(k);
    for(int i=0;i<n;i++)
    {
        ta[i]=a[i];

    }
    for(int i=n;i<s;i++)
    {

        ta[i]=0;
    }
    NTT(ta,s,1);

    NTT(b,s,1);

    for(int i=0;i<s;i++)
    {
        b[i]=(2ll-ta[i]*b[i]%mod+mod)*b[i]%mod;

    }
    NTT(b,s,-1);

    for(int i=n;i<s;i++)
    {
        b[i]=0;
    }

}

void sqrt(ll *a,ll *b, int n)
{

    if(n==1)
    {
        b[0]=1;
        return ;
    }

    sqrt(a,b,(n+1)>>1);

    int k=1,s=2;

    while((1<<k)<n+n-1)
    {
        k++;

        s<<=1;

    }


    for(int i=0;i<s;i++)
    {
        tb[i]=0;
    }

    getinv(b,tb,n);

    mul(a,tb,tb,n,n);

    for(int i=0;i<s;i++)
    {
        b[i]=(b[i]+tb[i])*inv%mod;

    }

}
int main ()
{
    int n;
    cin>>n;

    for(int i=0;i<n;i++)
    {
        cin>>A[i];

    }

    sqrt(A,B,n);

    for(int i=0;i<n;i++)
    {
        cout<<B[i]<<" ";

    }
    return 0;

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qinsanma and Code

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值