Live2D

题解 多项式多点求值

题目传送门

题目大意

给出一个n次多项式f,有m个点,分别为{a1,a2,...,am},请您求出对于任意i[1,m],求出f(ai)

n,m64000

思路

我用的是一种人尽皆知的方法,即多项式取模的Θ(nlog2n)的方法,常数极大,而且因为我自身封装的问题,导致我的空间消耗也极大。(自闭了)

我们发现,如果我们构造P(x)=i=1m(xai),那么我们假设F(x)=P(x)D(x)+R(x),那么对于i[1,m],F(ai)=R(ai)。于是,我们可以得到一个非常naive的想法,即一直多项式取模,模到最后只剩下常数项就是答案。

根据主定理,时间复杂度为Θ(nlog2n),因为多项式取模时间复杂度为Θ(nlogn)

Code

Copy
#include <bits/stdc++.h> using namespace std; #define SZ(x) ((int)x.size()) #define Int register int #define mod 998244353 #define MAXN 1000005 int mul (int a,int b){return 1ll * a * b % mod;} int dec (int a,int b){return a >= b ? a - b : a + mod - b;} int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;} int qkpow (int a,int k){ int res = 1;for (;k;k >>= 1,a = 1ll * a * a % mod) if (k & 1) res = 1ll * res * a % mod; return res; } int inv (int x){return qkpow (x,mod - 2);} typedef vector <int> poly; int w[MAXN],rev[MAXN]; void init_ntt (){ int lim = 1 << 18; for (Int i = 0;i < lim;++ i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << 17); int Wn = qkpow (3,(mod - 1) / lim);w[lim >> 1] = 1; for (Int i = lim / 2 + 1;i < lim;++ i) w[i] = mul (w[i - 1],Wn); for (Int i = lim / 2 - 1;i;-- i) w[i] = w[i << 1]; } void ntt (poly &a,int lim,int type){ #define G 3 #define Gi 332748118 static int d[MAXN]; for (Int i = 0,z = 18 - __builtin_ctz(lim);i < lim;++ i) d[rev[i] >> z] = a[i]; for (Int i = 1;i < lim;i <<= 1) for (Int j = 0;j < lim;j += i << 1) for (Int k = 0;k < i;++ k){ int x = mul (w[i + k],d[i + j + k]); d[i + j + k] = dec (d[j + k],x),d[j + k] = add (d[j + k],x); } for (Int i = 0;i < lim;++ i) a[i] = d[i] % mod; if (type == -1){ reverse (a.begin() + 1,a.begin() + lim); for (Int i = 0,Inv = inv (lim);i < lim;++ i) a[i] = mul (a[i],Inv); } #undef G #undef Gi } poly operator + (poly a,poly b){ a.resize (max (SZ (a),SZ (b))); for (Int i = 0;i < SZ (b);++ i) a[i] = add (a[i],b[i]); return a; } poly operator - (poly a,poly b){ a.resize (max (SZ (a),SZ (b))); for (Int i = 0;i < SZ (b);++ i) a[i] = dec (a[i],b[i]); return a; } poly operator * (poly a,int b){ for (Int i = 0;i < SZ (a);++ i) a[i] = mul (a[i],b); return a; } poly operator * (poly a,poly b){ int d = SZ (a) + SZ (b) - 1,lim = 1;while (lim < d) lim <<= 1; a.resize (lim),b.resize (lim); ntt (a,lim,1),ntt (b,lim,1); for (Int i = 0;i < lim;++ i) a[i] = mul (a[i],b[i]); ntt (a,lim,-1),a.resize (d); return a; } poly inv (poly a,int n){ poly b(1,inv (a[0])),c; for (Int l = 4;(l >> 2) < n;l <<= 1){ c.resize (l >> 1); for (Int i = 0;i < (l >> 1);++ i) c[i] = i < n ? a[i] : 0; c.resize (l),b.resize (l); ntt (c,l,1),ntt (b,l,1); for (Int i = 0;i < l;++ i) b[i] = mul (b[i],dec (2,mul (b[i],c[i]))); ntt (b,l,-1),b.resize (l >> 1); } b.resize (n); return b; } poly inv (poly a){return inv (a,SZ (a));} poly Mod (poly F,poly G){ int n = SZ (F) - 1,m = SZ (G) - 1;poly Q;Q.resize (m + 1);for (Int i = 0;i <= m;++ i) Q[i] = G[i]; reverse (F.begin(),F.end()),reverse (G.begin(),G.end()),reverse (Q.begin(),Q.end()),Q.resize (n - m + 1),Q = inv (Q) * F,Q.resize (n - m + 1),reverse (Q.begin(),Q.end()); reverse (F.begin(),F.end()),reverse (G.begin(),G.end()),Q = G * Q,Q.resize (m),Q = F - Q,Q.resize (m); return Q; } template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;} template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);} template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');} int n,m,a[MAXN]; poly A,DR[MAXN << 2]; void divide1 (int i,int l,int r){ if (l == r) return DR[i].resize (2),DR[i][0] = mod - a[l],DR[i][1] = 1,void (); int mid = (l + r) >> 1;divide1 (i << 1,l,mid),divide1 (i << 1 | 1,mid + 1,r); DR[i] = DR[i << 1] * DR[i << 1 | 1]; } void divide2 (int i,int l,int r,poly AA){ if (l == r) return write (AA[0]),putchar ('\n'),void (); poly B = Mod (AA,DR[i << 1]);int mid = (l + r) >> 1;divide2 (i << 1,l,mid,B);B = Mod (AA,DR[i << 1 | 1]);divide2 (i << 1 | 1,mid + 1,r,B); } signed main(){ init_ntt(),read (n,m),A.resize (n + 1);for (Int i = 0;i <= n;++ i) read (A[i]);for (Int i = 1;i <= m;++ i) read (a[i]); divide1 (1,1,m),divide2 (1,1,m,A); return 0; }
posted @   Dark_Romance  阅读(399)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示