數學推導題,NTT,快速數論變換,Wannafly-導數卷積

導數卷積


題目描述

在這裏插入圖片描述

題解

參考了一下標程的推導過程,因爲這個推導對我這種數學弱渣真的有點難鴨.

[1]f(x)f(x)ii次導函數:

f(i)(x)=aii!0!+ai+1(i+1)!1!x1+...+an1(n1)!(n1i)!xn1if^{(i)}(x) = a_{i}*\frac{i!}{0!} + a_{i+1}*\frac{(i+1)!}{1!}*x^{1} +...+a_{n-1}*\frac{(n-1)!}{(n-1-i)!}*x^{n-1-i}

[2]f(x)f(x)ni1n-i-1次導函數:

f(ni1)(x)=ani1(n1i)!0!+ani(ni)!1!x1+...+an1(n1)!i!xif^{(n-i-1)}(x) = a_{n-i-1}*\frac{(n-1-i)!}{0!} + a_{n-i}*\frac{(n-i)!}{1!}*x^{1} +...+a_{n-1}*\frac{(n-1)!}{i!}*x^{i}

對於積式f(i)(x)f(n1i)(x)f^{(i)}(x)f^{(n-1-i)}(x)結果中,次數爲dd的項xdx^d前的係數應該是:

t=0dai+t(i+t)!t!ani1+(dt)(ni1+(dt))!(dt)!\sum_{t = 0}^{d}a_{i+t}*\frac{(i+t)!}{t!}*a_{n-i-1+(d-t)}*\frac{(n-i-1+(d-t))!}{(d-t)!}

Fi=aii!F_i = a_i * i!

換種寫法:

t=0dFi+t1t!Fn1+d(i+t)1(dt)!\sum_{t = 0}^{d}F_{i+t}*\frac{1}{t!}*F_{n-1+d-(i+t)}*\frac{1}{(d-t)!}

對所有的積式求和得到:

i=0n1t=0dFi+t1t!Fn1+d(i+t)1(dt)!\sum_{i= 0}^{n-1}\sum_{t = 0}^{d}F_{i+t}*\frac{1}{t!}*F_{n-1+d-(i+t)}*\frac{1}{(d-t)!}

=i=0n1+dFiFn1+dij=0d1j!(dj)!=\sum^{n-1+d}_{i=0}F_{i}*F_{n-1+d-i}*\sum^{d}_{j=0}\frac{1}{j!(d-j)!}

在上個式子中必須要滿足n1+din1n-1+d-i \le n-1, 即,did \le i ,不然Fn1+diF_{n-1+d-i}將變成00,不過對答案沒有影響.

jj的取值範圍是j:[0,min(d,i)]j:[0,min(d,i)],也就是j:[0,d]j:[0,d].

因此上個式子就是,

=i=0n1+dFiFn1+di2dd!=2dd!i=0n1+dFiFn1+di=\sum^{n-1+d}_{i=0}F_{i}*F_{n-1+d-i}*\frac{2^d}{d!} = \frac{2^d}{d!} *\sum^{n-1+d}_{i=0}F_{i}*F_{n-1+d-i}

對後面的部分i=0n1+dFiFn1+di\sum^{n-1+d}_{i=0}F_{i}*F_{n-1+d-i}直接套用NTTNTT來求就可以了.

代碼

#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;
#define rep(i,a,b) for(int i = a;i <= b;++i)
typedef long long LL;
const int N = 1 << 20;
const int P = 998244353;
const int G = 3;
const int NUM = 20;

LL  wn[NUM];
LL  a[N], b[N];

LL quick_mod(LL a, LL b, LL m)
{
    LL ans = 1;
    a %= m;
    while(b)
    {
        if(b & 1)
        {
            ans = ans * a % m;
            b--;
        }
        b >>= 1;
        a = a * a % m;
    }
    return ans;
}

void GetWn()
{
    for(int i = 0; i < NUM; i++)
    {
        int t = 1 << i;
        wn[i] = quick_mod(G, (P - 1) / t, P);
    }
}
void Rader(LL a[], int len)
{
    int j = len >> 1;
    for(int i = 1; i < len - 1; i++)
    {
        if(i < j) swap(a[i], a[j]);
        int k = len >> 1;
        while(j >= k)
        {
            j -= k;
            k >>= 1;
        }
        if(j < k) j += k;
    }
}

void NTT(LL a[], int len, int on)
{
    Rader(a, len);
    int id = 0;
    for(int h = 2; h <= len; h <<= 1)
    {
        id++;
        for(int j = 0; j < len; j += h)
        {
            LL w = 1;
            for(int k = j; k < j + h / 2; k++)
            {
                LL u = a[k] % P;
                LL t = w * a[k + h / 2] % P;
                a[k] = (u + t) % P;
                a[k + h / 2] = (u - t + P) % P;
                w = w * wn[id] % P;
            }
        }
    }
    if(on == -1)
    {
        for(int i = 1; i < len / 2; i++)
            swap(a[i], a[len - i]);
        LL inv = quick_mod(len, P - 2, P);
        for(int i = 0; i < len; i++)
            a[i] = a[i] * inv % P;
    }
}

void Conv(LL a[], LL b[], int n)
{
    NTT(a, n, 1);
    NTT(b, n, 1);
    for(int i = 0; i < n; i++)
        a[i] = a[i] * b[i] % P;
    NTT(a, n, -1);
}
int n;
LL Fac[N],iFac[N];
int main()
{
    GetWn();
	Fac[0] = 1;
	rep(i,1,N-1) 
		Fac[i] = Fac[i-1] * i % P;
	rep(i,0,N-1)
		iFac[i] = quick_mod(Fac[i],P-2,P);
	ios::sync_with_stdio(false);
	cin >> n;
	rep(i,0,n-1) {
		std::cin >> a[i];
		a[i] = b[i] = a[i] * Fac[i] % P;
	}
	int len = 1;
	while(len < n) len <<= 1;
    len <<= 1;
	Conv(a,b,len);
	rep(i,0,n-1) {
		std::cout << a[n-1+i] * quick_mod(2,i,P) % P * iFac[i] % P << " ";
	}
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章