题解 普通多项式转下降幂多项式

题目传送门

题目大意

给出一个\(n\)次普通多项式\(F(x)=\sum_{i=0}^{n-1} a_ix^i\),求出一个下降幂多项式\(G(x)=\sum_{i=0}^{n-1} b_ix^{\underline{i}}\),使得\(F(x)=G(x)\)

\(n\le 10^5\)

思路

这个题其实推式子的方法有很多种,这里介绍题解里面没有提到的两种方法。第一种方法就是借用一下下降幂多项式乘法里面的式子,直接多点求值,然后用它的\(\texttt{EGF}\)乘上\(e^{-x}\)就是下降幂多项式。

第二种方法就是用斯特林反演+第二类斯特林的表达公式推式子,这里讲一下第二种。

因为我们知道:

\[x^{\underline{n}}=\sum_{i=0}^{n} (-1)^{n-i} \begin{bmatrix} n\\i\end{bmatrix}x^i
\]

于是,我们可以得到:

\[a_i = \sum_{x=i}^{n} (-1)^{x-i} \begin{bmatrix}x\\i \end{bmatrix} b_x
\]

通过斯特林反演可以得到:

\[b_i=\sum_{x=i}^{n} \begin{Bmatrix}x\\i\end{Bmatrix}a_x
\]

又因为我们知道:

\[\begin{Bmatrix}n\\m\end{Bmatrix}=\frac{1}{m!}\sum_{i=0}^{m} \binom{m}{i} (-1)^{m-i} i^n
\]

所以我们可以得到:

\[b_i=\sum_{x=i}^{n} \frac{a_x}{i!} \sum_{k=0}^{i} \binom{i}{k}(-1)^{k-i}k^x
\]

调换求和顺序、拆开组合数可以得到:

\[b_i=\sum_{k=0}^{i} (\frac{(-1)^{i-k}}{(i-k)!}\frac{1}{k!}\sum_{j=0}^{n-1} a_jk^j)
\]

然后这个东西括号里面的\(\sum\)可以用多点求值求出来。其实和上面那个方法的最后的式子是一样的。

这道题有点卡常,所以多点求值的部分借鉴了\(\texttt{bztMinamoto}\)的思路,就是当区间长度比较小的时候,我们直接循环展开暴力,经过实测,不加上这种优化我的代码只有\(30\),加上之后开了 O2 \(\texttt{10.84s}\)通过了。

时间复杂度\(\Theta(n\log^2n)\)

\(\texttt{Code}\)

#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] = dec (a[i],b[i]);
    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,fac[MAXN],ifac[MAXN];
poly A,BB,CC,DR[MAXN << 2];

void divide1 (int i,int l,int r){
    if (l == r) return DR[i].resize (2),DR[i][0] = mod - 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 CC[l] = AA[0],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),A.resize (n);
    fac[0] = 1;for (Int i = 1;i <= n;++ i) fac[i] = mul (fac[i - 1],i);
    ifac[n] = inv (fac[n]);for (Int i = n;i;-- i) ifac[i - 1] = mul (ifac[i],i);
    for (Int i = 0;i < n;++ i) read (A[i]);CC.resize (n);divide1 (1,0,n - 1),divide2 (1,0,n - 1,A),BB.resize (n);
    for (Int i = 0;i < n;++ i) BB[i] = i & 1 ? mod - ifac[i] : ifac[i],CC[i] = mul (CC[i],ifac[i]);BB = BB * CC;
    for (Int i = 0;i < n;++ i) write (BB[i]),putchar (' ');
    putchar ('\n');
    return 0;
}
```题解 普通多项式转下降幂多项式

原文链接: https://www.cnblogs.com/Dark-Romance/p/13341290.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    题解 普通多项式转下降幂多项式

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/368581

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月2日 下午6:29
下一篇 2023年3月2日 下午6:30

相关推荐