luogu5050(多项式多点求值)

题意

给定一个 $n-1$ 次多项式 $F(x)$ 和 $m$ 项序列 ${a_i}$ ,对 $\forall i\in[1,m]$,求 $F(a_i)$

题解

主要是利用分治的思想将求值的规模逐渐减少。。

若给定多项式 $F(x)$ ,要在 $X={x_0,x_1..x_n}$ 上进行多点求值

那么可以将 $X$ 分成两半, $X1={x_0,x_1..x{\lfloor\frac{n}{2} \rfloor} }$ 和 $X2={x{\lfloor\frac{n}{2} \rfloor+1}…x_n}$

另 $A(x)=\prod{x_i\in X} (x-x_i)$ ,$A_1(x)=\prod{xi\in X_1} (x-x_i)$ ,$A_2(x)=\prod{x_i\in X_2} (x-x_i)$

那么可以构造 $F_1(x)=F(x)\bmod{A_1(x)}$ 和 $F_2(x)=F(x)\bmod{A_2(x)}$

设 $F(x)=Q(x)A_1(x)+F_1(x)$

那么 $\forall x_i\in X_1$ ,$F(x_i)=Q(x_i)A_1(x_i)+F_1(x_i)=F_1(x_i)$

同理 $\forall x_i\in X_2$ ,$F(x_i)=F_2(x_i)$

这样问题就简化成了在 $X_1$ 上对 $F_1(x)$ 进行多点求值和在 $X_2$ 上对 $F_2(x)$ 进行多点求值

对 $A(x)$ 同样可以利用分治预处理出来,两者的复杂度均为 $O(nlog^2n)$ ,但是常数巨大。。




代码

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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/**
*         ┏┓    ┏┓
*         ┏┛┗━━━━━━━┛┗━━━┓
*         ┃       ┃  
*         ┃   ━    ┃
*         ┃ >   < ┃
*         ┃       ┃
*         ┃... ⌒ ...  ┃
*         ┃ ┃
*         ┗━┓ ┏━┛
*          ┃ ┃ 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 mid (x+y>>1)
#define sqr(x) ((x)*(x))
#define NM 70000
#define nm 400005
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,m;
ll a[NM],b[NM];

inline void reduce(ll&x){x+=x>>63&inf;}

inline ll qpow(ll base, ll p) {
static ll res;
for (res = 1; p; p >>= 1, base = (base) * base % inf) if (p & 1) res = (res) * base % inf;
return res;
}



//ll qpow(ll x,ll t){return t?qpow(sqr(x)%inf,t>>1)*(t&1?x:1ll)%inf:1ll;}
namespace Poly{
int lim,bit,rev[NM];
ll invn,W[NM],w[NM];
inline void clear(ll*a,ll*b){if(a<b)memset(a,0,sizeof(ll)*(b-a));}
inline void init(int m){
for(lim=1,bit=0;lim<m;lim<<=1)bit++;invn=qpow(lim,inf-2);
inc(i,0,lim-1)rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
ll t=qpow(3,(inf-1)/lim);W[0]=1;
inc(i,1,lim)W[i]=W[i-1]*t%inf;
}
inline void fft(ll*a,int f=0){
int n=lim;
inc(i,0,n-1)if(i<rev[i])std::swap(a[i],a[rev[i]]);
for(register int k=1;k<n;k<<=1){
int t=n/k>>1;
for(register int i=0,j=0;i<k;i++,j+=t)w[i]=W[f?n-j:j];
for(register int i=0;i<n;i+=k<<1)
for(register int j=0;j<k;j++){
ll x=a[i+j],y=w[j]*a[i+j+k]%inf;
reduce(a[i+j]=x+y-inf);reduce(a[i+j+k]=x-y);
}
}
if(f)inc(i,0,n-1)a[i]=a[i]*invn%inf;
}
ll _a[NM];
inline 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);init(m<<1);
std::copy(a,a+m,_a);clear(_a+m,_a+lim);clear(b+m,b+lim);
fft(b);fft(_a);
inc(i,0,lim-1)b[i]=b[i]*(2-_a[i]*b[i]%inf+inf)%inf;
fft(b,1);clear(b+m,b+lim);
}
ll _b[NM];
inline void div(ll*c,ll*d,ll*a,ll*b,int n,int m){
std::reverse_copy(a,a+n,c);std::reverse_copy(b,b+m,d);
inv(_b,d,n-m+1);std::reverse(d,d+m);
init(n-m+1<<1);clear(c+n-m+1,c+lim);
fft(_b);fft(c);
inc(i,0,lim-1)c[i]=c[i]*_b[i]%inf;
fft(c,1);std::reverse(c,c+n-m+1);clear(c+n-m+1,c+lim);
init(n);std::copy(c,c+n-m+1,_b);clear(_b+n-m+1,_b+lim);
m--;clear(d+m,d+lim);fft(_b);fft(d);
inc(i,0,lim-1)d[i]=d[i]*_b[i]%inf;
fft(d,1);clear(d+m,d+lim);clear(_b,_b+lim);
inc(i,0,m-1)reduce(d[i]=a[i]-d[i]);
}
std::vector<ll>p[NM<<1],q[NM<<1];ll _c[NM];
inline void build(int i,int x,int y){
if(x==y){p[i].push_back(b[x]);p[i].push_back(1);return;}
build(i<<1,x,mid);build(i<<1|1,mid+1,y);
int n=p[i<<1].size(),m=p[i<<1|1].size();init(n+m-1);
std::copy(p[i<<1].begin(),p[i<<1].end(),_a);clear(_a+n,_a+lim);
std::copy(p[i<<1|1].begin(),p[i<<1|1].end(),_b);clear(_b+m,_b+lim);
fft(_a);fft(_b);
inc(j,0,lim-1)_c[j]=_a[j]*_b[j]%inf;
fft(_c,1);p[i].assign(_c,_c+n+m-1);
}
ll ans[NM],_d[NM],tmp[NM],ret[NM];
inline void DIV(int x,int y){
if(q[x].size()<p[y].size()){q[y]=q[x];return;}
std::copy(q[x].begin(),q[x].end(),_c);std::copy(p[y].begin(),p[y].end(),_d);
div(tmp,ret,_c,_d,q[x].size(),p[y].size());q[y].assign(ret,ret+p[y].size()-1);
while(!q[y].back())q[y].pop_back();
}
inline void cal(int i,int x,int y){
if(x==y){ans[x]=q[i][0];return;}
DIV(i,i<<1);DIV(i,i<<1|1);
cal(i<<1,x,mid);cal(i<<1|1,mid+1,y);
}
}


int main(){
n=read()+1;m=read();
inc(i,0,n-1)a[i]=read();
inc(i,1,m)reduce(b[i]=-read());
Poly::build(1,1,m);
Poly::q[0].assign(a,a+n);
Poly::DIV(0,1);
Poly::cal(1,1,m);
inc(i,1,m)printf("%lld\n",Poly::ans[i]);
return 0;
}