多项式全家桶递推版

有的多项式题不需要用到 (O(nlog n)) 的多项式全家桶,所以来写下递推的 (O(n^2)) 做法。

多项式求逆

(B(x))(A(x)) 的逆,那么:

[egin{aligned}B(x)A(x)&=[n==0]\sum_{i=0}^nA_iB_{n-i}&=0(n>0),B_0=frac{1}{A_0}(n=0)\B_n&=-frac{1}{A_0}sum_{i=1}^nA_iB_{n-i}end{aligned} ]

Code

void INV(int *a,int *ans,int n)
{
    for (int i = 0;i <= n;i++)
        ans[i] = 0;
    ans[0] = mypow(a[0],p - 2);
    for (int i = 1;i <= n;i++)
    {
        for (int j = 1;j <= i;i++)
            ans[i] -= 1ll * a[j] * ans[i - j] % p,ans %= p;
        ans[i] = 1ll * ans[i] * ans[0] % p;
    }
}

多项式快速幂

(B(x)=A^k(x)) ,那么:

[egin{aligned}B'(x)&=kA'(x)A^{k-1}(x)\B'(x)A(x)&=kA'(x)B(x)\sum_{i=0}^nB'_iA_{n-i}&=ksum_{i=0}^nA'_iB_{n-i}\sum_{i=0}^nB_{i+1}(i+1)A_{n-i}&=ksum_{i=0}A_{i+1}(i+1)B_{n-i}\B_{n+1}=frac{k}{A_0(n+1)}&(sum_{i=0}^nA_{i+1}(i+1)B_{n-i}-sum_{i=0}^{n-1}B_{i+1}(i+1)A_{n-i})end{aligned} ]

边界 (B_0=A_0^k)

Code

void Polypow(int *a,int *ans,int n,int k)
{
    for (int i = 0;i <= n;i++)
        ans[i] = 0;
    int st = 0,sst = 0;
    while (!a[st])
        st++;
    sst = st;
    st = min(st * k - 1,n);
    if (st == n)
        return;
    st++;
    ans[st] = mypow(a[sst],k);
    int inv = mypow(a[sst],p - 2);
    for (int i = 1;i <= n - st;i++)
    {
        for (int j = 0;j < i;j++)
            ans[i + st] += 1ll * k * a[j + 1 + sst] % p * (j + 1) % p * ans[i - 1 - j + st] % p,ans[i + st] %= p;
        for (int j = 0;j < i - 1;j++)
            ans[i + st] -= 1ll * a[i - 1 - j + sst] * ans[j + 1 + st] % p * (j + 1) % p,ans[i + st] %= p;
        ans[i + st] = 1ll * ans[i + st] * inv % p * Inv[i] % p;
    }
}

Ln

(B(x)=ln(A(x))) ,那么有 (B'(x)=frac{A'(x)}{A(x)}) ,那么:

[egin{aligned}A'(x)&=B'(x)A(x)\A'_n&=sum_{i=0}^nA_iB'_{n-i}\A_{n+1}(n+1)&=sum_{i=0}^nA_iB_{n-i+1}(n-i+1)\B_{n+1}&=frac{1}{n+1}(A_{n+1}(n+1)-sum_{i=1}^nA_iB_{n-i+1}(n-i+1))end{aligned} ]

要求 (A_0=1) ,边界 (B_0=0)

Code

void Ln(int *a,int *ans,int n)
{
    for (int i = 0;i <= n;i++)
        ans[i] = 0;
    for (int i = 1;i <= n;i++)
    {
        ans[i] = 1ll * a[i] * i % p;
        for (int j = 1;j < i;j++)
            ans[i] -= 1ll * a[j] * ans[i - j] % p * (i - j) % p,ans[i] %= p;
        ans[i] = 1ll * ans[i] * Inv[i] % p;
    }
}

exp

(B(x)=e^{A(x)}) ,那么:

[egin{aligned}B'_n&=sum_{i=0}^nB_iA_{n-i}\B_{n+1}&=frac{1}{n+1}sum_{i=0}^nB_iA_{n-i+1}(n-i+1)end{aligned} ]

要求 (A_0=0) ,边界 (B_0=1)

Code

void exp(int *a,int *ans,int n)
{
    for (int i = 0;i <= n;i++)
        ans[i] = 0;
    ans[0] = 1;
    for (int i = 1;i <= n;i++)
    {
        for (int j = 0;j < i;j++)
            ans[i] += 1ll * ans[j] * a[i - j] % p * (i - j) % p,ans[i] %= p;
        ans[i] = 1ll * ans[i] * Inv[i] % p;
    }
}

kexp

(B(x)=sum_{i=0}^kfrac{A^i(x)}{i!}) ,那么:

[egin{aligned}B'(x)&=sum_{i=0}^kfrac{{A^i}'(x)}{i!}\B'(x)&=sum_{i=0}^kfrac{A^{i-1}(x)iA'(x)}{i!}\B'(x)&=A'(x)(B(x)-frac{A^k(x)}{k!})end{aligned} ]

(C(x)=frac{A^k(x)}{k!}) ,可以通过多项式快速幂求出,然后就有:

[egin{aligned}B'(x)&=A'(x)(B(x)-C(x))\B'_{n}&=sum_{i=0}^nA'_{i}(B_{n-i}-C_{n-i})\B_{n+1}&=frac{1}{n+1}sum_{i=0}^nA_{i+1}(i+1)(B_{n-i}-C(n-i))end{aligned} ]

Code

void kexp(int *a,int *ans,int n,int k)
{
    int inv = 1,res = 1;
    for (int i = 1;i <= k;i++)
        inv = 1ll * inv * i % p;
    inv = mypow(inv,p - 2);
    Polypow(a,tmp,n,k);
    for (int i = 0;i <= n;i++)
        tmp[i] = 1ll * tmp[i] * inv % p;
    for (int i = 0;i <= n;i++)
        ans[i] = 0;
    ans[0] = 1;
    for (int i = 1;i <= k;i++)
    {
        res = 1ll * res * a[0] % p * Inv[i] % p;
        ans[0] += res;
        ans[0] %= p;
    }
    for (int i = 1;i <= n;i++)
    {
        for (int j = 0;j < i;j++)
            ans[i] += 1ll * a[j + 1] * (j + 1) % p * ((ans[i - j - 1] - tmp[i - j - 1]) % p) % p,ans[i] %= p;
        ans[i] = 1ll * ans[i] * Inv[i] % p;
    }
}
原文地址:https://www.cnblogs.com/sdlang/p/14299644.html