多项式开根
和exp大同小异
F
2
(
x
)
≡
A
(
x
)
(
m
o
d
x
n
)
F^2(x)\equiv A(x)\ (mod\ x^n)
F2(x)≡A(x) (mod xn)
G
(
F
(
x
)
)
=
F
2
(
x
)
−
A
(
x
)
G(F(x))=F^2(x)-A(x)
G(F(x))=F2(x)−A(x)
G
′
(
F
(
x
)
)
=
2
F
(
x
)
G'(F(x))=2F(x)
G′(F(x))=2F(x)
套牛顿迭代
F
(
x
)
=
F
0
(
x
)
−
G
(
F
0
(
x
)
)
G
′
(
F
0
(
x
)
)
=
F
0
2
(
x
)
−
A
(
x
)
2
F
0
(
x
)
F(x)=F_0(x)-\frac{G(F_0(x))}{G'(F_0(x))}=\frac{F_0^2(x)-A(x)}{2F_0(x)}
F(x)=F0(x)−G′(F0(x))G(F0(x))=2F0(x)F02(x)−A(x)
套一个求逆就行。
题目
https://www.luogu.com.cn/problem/CF438E
思路
设 f i f_i fi 表示 i i i 个点的答案, g i g_i gi 表示权值为 i i i 的点是否在集合里面
显然有递推式
f
n
=
∑
i
=
1
n
g
[
i
]
∑
j
=
1
n
−
i
f
j
f
n
−
i
−
j
f_n=\sum_{i=1}^{n}g[i]\sum_{j=1}^{n-i}f_jf_{n-i-j}
fn=i=1∑ng[i]j=1∑n−ifjfn−i−j
不难发现这是3个多项式卷在一起,即
F
=
G
∗
F
2
+
1
F=G*F^2+1
F=G∗F2+1
然后根据求根公式
F
=
1
±
1
−
4
G
2
G
F=\frac{1±\sqrt{1-4G}}{2G}
F=2G1±1−4G然后可以证明这里只能取负,好像是把0带进去?
发现 2 G 2G 2G 的0次项是0,不能求逆,所以要化简一下 F = 2 1 + 1 − 4 G F=\frac{2}{1+\sqrt{1-4G}} F=1+1−4G2
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=4e5+77,mod=998244353;
const ll g=3;
int r[N];
ll c[N],ia[N],G[N],a[N],b[N],C[N];
ll power(ll x,ll t)
{
ll b=1;
while(t)
{
if(t&1) b=b*x%mod; x=x*x%mod; t>>=1;
}
return b;
}
void dft(ll *a,int n,int f)
{
for(int i=1; i<=n; i++) if(i<r[i]) swap(a[i],a[r[i]]);
for(int i=2; i<=n; i<<=1)
{
int now=i>>1; ll wn=power(g,(mod-1)/i);
if(f==-1) wn=power(wn,mod-2);
for(int j=0; j<n; j+=i)
{
ll x,y,w=1;
for(int k=j; k<j+now; k++,w=w*wn%mod)
{
x=a[k],y=w*a[k+now]%mod;
a[k]=(x+y)%mod,a[k+now]=(x-y+mod)%mod;
}
}
}
if(f==-1) for(int i=0; i<n; i++) a[i]=a[i]*power(n,mod-2)%mod;
}
void inv(int n,ll *a,ll *b)
{
if(n==1)
{
b[0]=power(a[0],mod-2); return;
}
inv(n>>1,a,b);
int len=1,lg=0;
while(len<n*2) len<<=1,lg++;
for(int i=1; i<=len; i++) r[i]=((r[i>>1]>>1)|((i&1)<<(lg-1)));
for(int i=0; i<n; i++) c[i]=a[i];
dft(c,len,1),dft(b,len,1);
for(int i=0; i<len; i++) b[i]=(2-c[i]*b[i]%mod+mod)%mod*b[i]%mod;
dft(b,len,-1);
// for(int i=n; i<len; i++) b[i]=0;
for(int i=0; i<len; i++) c[i]=0; for(int i=n; i<len; i++) b[i]=0;
}
void Sqrt(int n,ll *a,ll *b)
{
if(n==1)
{
b[0]=1; return;
}
Sqrt(n>>1,a,b);
inv(n,b,ia);
int len=1,lg=0; ll inv2=499122177;
while(len<n*2) len<<=1,lg++;
for(int i=1; i<=len; i++) r[i]=(r[i>>1]>>1)|((i&1)<<(lg-1));
for(int i=0; i<n; i++) C[i]=a[i];
dft(C,len,1); dft(b,len,1); dft(ia,len,1);
for(int i=0; i<len; i++) b[i]=(b[i]+C[i]*ia[i]%mod)%mod;
dft(b,len,-1);
for(int i=0; i<n; i++) b[i]=b[i]*inv2%mod; for(int i=n; i<len; i++) b[i]=0;
// for(int i=0; i<n; i++) printf("%lld ",b[i]); printf("\n");
for(int i=0; i<len; i++) C[i]=ia[i]=0;
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1,x; i<=n; i++) scanf("%d",&x),G[x]=mod-4;
G[0]++;
int len=1;
while(len<=m) len<<=1;
Sqrt(len,G,a);
a[0]++;
inv(len,a,b);
for(int i=1; i<=m; i++) printf("%lld\n",b[i]*2%mod);
}