luogu5277(多项式开方)

题意

给定一个 $n-1$ 次多项式 $F(x)$ ,求 $G(x)$ 使得 $G^2(x)\equiv F(x)\pmod {x^n}$

题解

仿照 多项式逆元的证明方法 进行证明即可

求 $B(x)$ 满足

当 $m=1$ ,只需求

即可

这个一般用二次剩余做(可是窝太弱还不会),所以留个坑

当 $m>1$ ,

假设已知 $B’(x)$

那么

然后直接递归算就可以了

复杂度为 $T(m)=T(\frac{m}{2})+O(mlogm)=O(mlogm)$ ,虽然套了多项式逆元但是复杂度并没有变大2333

最后多项式平方根的存在性依旧取决与 $a_0$ 是否为二次剩余

如果二次剩余方程有多解,那么该多项式也有多个平方根

然而题目要求最小的常系数,坑啊。。




代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/**
*         ┏┓    ┏┓
*         ┏┛┗━━━━━━━┛┗━━━┓
*         ┃       ┃  
*         ┃   ━    ┃
*         ┃ >   < ┃
*         ┃       ┃
*         ┃... ⌒ ...  ┃
*         ┃ ┃
*         ┗━┓ ┏━┛
*          ┃ ┃ Code is far away from bug with the animal protecting          
*          ┃ ┃ 神兽保佑,代码无bug
*          ┃ ┃           
*          ┃ ┃       
*          ┃ ┃
*          ┃ ┃           
*          ┃ ┗━━━┓
*          ┃ ┣┓
*          ┃ ┏┛
*          ┗┓┓┏━━━━━━━━┳┓┏┛
*           ┃┫┫ ┃┫┫
*           ┗┻┛ ┗┻┛
*/

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<set>
#include<bitset>
#include<complex>
#include<cstdlib>
#include<assert.h>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-8
#define succ(x) (1<<x)
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define NM 300005
#define nm 300005
using namespace std;
const double pi=acos(-1);
const ll inf=998244353;
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}




int n;
ll a[NM],b[NM],_a[NM],_b[NM];

ll qpow(ll x,ll t){return t?qpow(sqr(x)%inf,t>>1)*(t&1?x:1ll)%inf:1ll;}

struct FFT{
int n,bit,rev[NM];
ll b[NM],invn;
void fft(ll*a,int f){
inc(i,0,n-1)if(i<rev[i])swap(a[i],a[rev[i]]);
for(int k=1;k<n;k<<=1){
ll t=qpow(3,(inf-1)/k/2);if(f==-1)t=qpow(t,inf-2);
for(int i=0;i<n;i+=k<<1){
ll w=1;
for(int j=0;j<k;j++,w=w*t%inf){
ll x=a[i+j],y=w*a[i+j+k]%inf;
a[i+j]=(x+y)%inf;a[i+j+k]=(x-y+inf)%inf;
}
}
}
}
int plu(ll*a,ll*_b,int p,int m){
inc(i,0,m-1)b[i]=_b[i];
for(n=p+m+1,bit=0;succ(bit)<n;bit++);n=succ(bit);
invn=qpow(n,inf-2);inc(i,p,n-1)a[i]=0;
inc(i,1,n-1)rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
fft(a,1);fft(b,1);inc(i,0,n-1)a[i]=a[i]*b[i]%inf;
fft(a,-1);inc(i,0,n-1)a[i]=a[i]*invn%inf;
inc(i,0,n-1)b[i]=0;
return m+p;
}
}fft;

ll Sqrt(ll t){
ll a=0,w;
if(qpow(t,inf-1>>1)+1==inf)return -1;
srand(time(0));
do{
a=rand()%inf;
w=(sqr(a)-t+inf)%inf;
}while(qpow(w,inf-1>>1)+1!=inf);
ll ans=1,_ans=0,_x,_y;
for(ll n=inf+1>>1,x=a,y=1;n;n>>=1){
if(n&1){
_x=ans*x%inf+_ans*y%inf*w%inf;
_y=ans*y%inf+_ans*x%inf;
ans=_x%inf;_ans=_y%inf;
}
_x=x*x%inf+y*y%inf*w%inf;
_y=2*x*y%inf;
x=_x%inf;y=_y%inf;
}
return ans;
}

void inv(ll*b,ll*a,int m){
if(m==1){b[0]=qpow(a[0],inf-2);return;}
inv(b,a,m+1>>1);
inc(i,0,m-1)_b[i]=b[i];
fft.plu(_b,a,m,m);
inc(i,0,m-1)_b[i]=-_b[i];
_b[0]+=2;
fft.plu(b,_b,m,m);
}

void _sqrt(ll*b,ll*a,int m){
if(m==1){b[0]=Sqrt(a[0]);b[0]=min(b[0],inf-b[0]);return;}
_sqrt(b,a,m+1>>1);
inv(_a,b,m);
fft.plu(b,b,m,m);
inc(i,0,m-1)b[i]+=a[i],_a[i]=_a[i]*(inf-inf/2)%inf,b[i]%=inf,_a[i]%=inf;
fft.plu(b,_a,m,m);
}

int main(){
n=read();inc(i,0,n-1)a[i]=read();
_sqrt(b,a,n);
inc(i,0,n-1)printf("%lld%c",b[i]," \n"[i==n-1]);
return 0;
}