HDU 6061 RXD and functions

题目链接:HDU-6061

题意:给定f(x),求f(x-A)各项系数。

思路:推导公式有如下结论:

然后用NTT解决即可。

代码:

#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
typedef long long LL;
const LL MAXN=1000000;
const LL MOD=998244353;

// NTT
// O(nlogn)
// Verified!
const LL P = MOD;
const LL G = 3;
const LL NUM = 30;

LL  wn[NUM];
LL A[MAXN], B[MAXN];

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(LL i=0; i<NUM; i++)
    {
        LL t = 1 << i;
        wn[i] = quick_mod(G, (P - 1) / t, P);
    }
}

void Prepare(char A[], char B[], LL a[], LL b[], LL &len)
{
    len = 1;
    LL len_A = strlen(A);
    LL len_B = strlen(B);
    while(len <= 2 * len_A || len <= 2 * len_B) len <<= 1;
    for(LL i=0; i<len_A; i++)
        A[len - 1 - i] = A[len_A - 1 - i];
    for(LL i=0; i<len - len_A; i++)
        A[i] = '0';
    for(LL i=0; i<len_B; i++)
        B[len - 1 - i] = B[len_B - 1 - i];
    for(LL i=0; i<len - len_B; i++)
        B[i] = '0';
    for(LL i=0; i<len; i++)
        a[len - 1 - i] = A[i] - '0';
    for(LL i=0; i<len; i++)
        b[len - 1 - i] = B[i] - '0';
}

void Rader(LL a[], LL len)
{
    LL j = len >> 1;
    for(LL i=1; i<len-1; i++)
    {
        if(i < j) swap(a[i], a[j]);
        LL k = len >> 1;
        while(j >= k)
        {
            j -= k;
            k >>= 1;
        }
        if(j < k) j += k;
    }
}

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

void Conv(LL a[], LL b[], LL n)
{
    NTT(a, n, 1);
    NTT(b, n, 1);
    for(LL i = 0; i < n; i++)
        a[i] = a[i] * b[i] % P;
    NTT(a, n, -1);
}

// 快速幂
// 求x^n%mod
// Verified!
LL powMod(LL x,LL n,LL mod)
{
    LL res=1;
    while(n>0)
    {
        if(n&1) res=res*x % mod;
        x=x*x % mod;
        n>>=1;
    }
    return res;
}
// 求逆元
// a和m应该互质
// 根据欧拉定理:a的逆即a^(phi(m)-1)
LL inv(LL a,LL m)
{
    return powMod(a,m-2,m);
    // return powMod(a,eularPhi(m)-1,m);
}
LL mi[MAXN],invsum[MAXN],fac[MAXN];
LL c[MAXN];
int main()
{
#ifdef LOCAL
    freopen("in.txt","r",stdin);
#endif
    GetWn();
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        n++;
        for(int i=0;i<n;i++) scanf("%lld",&c[i]);
        int m,s=0;
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            int tmp;
            scanf("%d",&tmp);
            s=(s+tmp)%MOD;
        }
        int len=1;
        while(len<2*n) len*=2;
        mi[0]=fac[0]=invsum[0]=invsum[1]=1;
        for(int i=1;i<n;i++)
            mi[i]=mi[i-1]*(P-s)%MOD;
        for(int i=1;i<n;i++)
            fac[i]=fac[i-1]*i%MOD;
        for(int i=2;i<n;i++)
            invsum[i]=inv(fac[i],MOD);
        for(int i=0;i<n;i++)
            A[i]=mi[i]*invsum[i]%MOD;
        for(int i=0;i<n;i++)
            B[i]=c[n-i-1]*fac[n-i-1]%MOD;
        for(int i=n;i<len;i++)
            A[i]=B[i]=0;
        Conv(A, B, len);
        for(int i=0;i<n;i++)
            printf("%lld ",A[n-i-1]*invsum[i]%MOD);
        printf("
");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zarth/p/7301392.html