zoukankan      html  css  js  c++  java
  • [洛谷P4726]【模板】多项式指数函数

    题目大意:给出$n-1$次多项式$A(x)$,求一个 $mod{x^n}$下的多项式$B(x)$,满足$B(x) equiv e^{A(x)}$。

    题解:(by Weng_weijie)

    泰勒展开:
    $$
    f(x)=f(x_0)+dfrac{f'(x_0)(x-x_0)}{1!}+dfrac{f''(x_0)(x-x_0)^2}{2!}+dots
    $$


    牛顿迭代:

    $$
    解关于 F(x) 的方程使得 G(F(x))equiv 0pmod{x^n} \
    假设 G(F_0(x)) equiv 0 pmod{x^{iglceildfrac{n}{2}ig ceil}} \
    对 G(F(x)) 在 F_0(x) 处泰勒展开得 \
    G(F(x)) equiv G(F_0(x)) + dfrac{G'(F_0(x))(F(x)-F_0(x))}{1!}+dots pmod{x^n} \
    又F(x)-F_0(x)equiv 0pmod{x^{iglceildfrac{n}{2}ig ceil}} \
    (F(x)-F_0(x))^2equiv 0pmod{x^n} \
    egin{align*}
    herefore G(F(x))&equiv G(F_0(x)) + G'(F_0(x))(F(x)-F_0(x))\
    &equiv 0pmod{x^n} \
    end{align*}\
    得到 F(x)=F_0(x)-dfrac{G(F_0(x))}{G'(F_0(x))}
    $$

    多项式指数函数:

    $$
    设F(x)=e^{A(x)}, ln F(x)=A(x), G(F(x))=ln F(x)-A(x) \
    于是就是解 G(F(x))=0,代入牛顿迭代公式得:\
    F(x)=F_0(x)(1-ln F_0(x)+A(x))
    $$
    卡点:

    C++ Code:

    #include <cstdio>
    #include <algorithm>
    #define maxn 1 << 18 | 3
    const int mod = 998244353, G = 3;
    inline int pw(int base, int p) {
    	int ans = 1;
    	for (; p; p >>= 1, base = 1ll * base * base % mod) if (p & 1) ans = 1ll * ans * base % mod;
    	return ans;
    }
    inline int Inv(int x) {return pw(x, mod - 2);}
    namespace Poly {
    	int lim, ilim, s, rev[maxn];
    	int Wn[maxn + 1], inv[maxn], __invnum;
    	#define i __invnum
    	inline int getinv(int n) {
    		while (i < n) {i++; inv[i] = 1ll * inv[mod % i] * (mod - mod / i) % mod;}
    		return inv[n];
    	}
    	inline void INIT() {inv[i = 1] = 1;}
    	#undef i
    	inline void init(int n) {
    		lim = 1, s = -1; while (lim < n) lim <<= 1, s++; ilim = getinv(lim);
    		for (int i = 0; i < lim; i++) rev[i] = rev[i >> 1] >> 1 | (i & 1) << s;
    		int t = pw(G, (mod - 1) / lim);
    		Wn[0] = 1; for (int i = 1; i <= lim; i++) Wn[i] = 1ll * Wn[i - 1] * t % mod;
    	}
    	
    	inline void up(int &a, int b) {if ((a += b) >= mod) a -= mod;}
    	inline void NTT(int *A, int op) {
    		for (int i = 0; i < lim; i++) if (i < rev[i]) std::swap(A[i], A[rev[i]]);
    		for (int mid = 1; mid < lim; mid <<= 1) {
    			int t = lim / mid >> 1;
    			for (int i = 0; i < lim; i += mid << 1) {
    				for (int j = 0; j < mid; j++) {
    					int W = op ? Wn[t * j] : Wn[lim - t * j];
    					int X = A[i + j], Y = 1ll * A[i + j + mid] * W % mod;
    					up(A[i + j], Y), up(A[i + j + mid] = X, mod - Y);
    				}
    			}
    		}
    		if (!op) for (int i = 0; i < lim; i++) A[i] = 1ll * A[i] * ilim % mod;
    	}
    	inline void DER(int *A, int *B, int n) {
    		B[n - 1] = 0; for (int i = 1; i < n; i++) B[i - 1] = 1ll * A[i] * i % mod;
    	}
    	inline void INT(int *A, int *B, int n) {
    		B[0] = 0; for (int i = 1; i < n; i++) B[i] = 1ll * A[i - 1] * inv[i] % mod;
    	}
    	int C[maxn];
    	void INV(int *A, int *B, int n) {
    		if (n == 1) {B[0] = Inv(A[0]); return ;}
    		INV(A, B, n + 1 >> 1);
    		init(n << 1);
    		for (int i = 0; i < n; i++) C[i] = A[i];
    		for (int i = n; i < lim; i++) C[i] = 0;
    		NTT(B, 1), NTT(C, 1);
    		for (int i = 0; i < lim; i++) B[i] = (2 + mod - 1ll * B[i] * C[i] % mod) * B[i] % mod;
    		NTT(B, 0);
    		for (int i = n; i < lim; i++) B[i] = 0;
    	}
    	int D[maxn];
    	inline void LN(int *A, int *B, int n) {
    		DER(A, D, n), INV(A, B, n);
    		init(n << 1);
    		NTT(B, 1), NTT(D, 1);
    		for (int i = 0; i < lim; i++) D[i] = 1ll * D[i] * B[i] % mod;
    		NTT(D, 0);
    		INT(D, B, n);
    		for (int i = n; i < lim; i++) B[i] = 0;
    	} 
    	int E[maxn], F[maxn];
    	void EXP(int *A, int *B, int n) {
    		if (n == 1) {B[0] = 1; return ;}
    		EXP(A, B, n + 1 >> 1);
    		for (int i = 0; i < n << 1; i++) E[i] = F[i] = 0;
    		LN(B, E, n);
    		for (int i = 0; i < n; i++) F[i] = A[i];
    		NTT(B, 1), NTT(E, 1), NTT(F, 1);
    		for (int i = 0; i < lim; i++) B[i] = (1ll + mod - E[i] + F[i]) * B[i] % mod;
    		NTT(B, 0);
    		for (int i = n; i < lim; i++) B[i] = 0;
    	}
    }
    int a[maxn], b[maxn], n;
    int main() {
    	scanf("%d", &n);
    	Poly::INIT();
    	for (int i = 0; i < n; i++) scanf("%d", a + i);
    	Poly::EXP(a, b, n);
    	for (int i = 0; i < n; i++) printf("%d ", b[i]); puts("");
    	return 0;
    }
    

      

  • 相关阅读:
    luogu P3239 [HNOI2015]亚瑟王
    android之软件键盘
    Eclipse输入智能提示设置
    防止反编译
    二进制数据读写
    数据类型转换
    类对象的读写文件
    Eclipse 快捷键
    修改IP
    Android eclipse 运行项目设置程序默认安装到SD卡
  • 原文地址:https://www.cnblogs.com/Memory-of-winter/p/9723954.html
Copyright © 2011-2022 走看看