2018.8.5T3(数学,NTT)

描述
题目太**鬼畜了,复制不下来
题目大意:给一个多项式 f(x) f ( x )
fi(x) f i ( x ) f(x) f ( x ) 的i阶导数
最后让我们求一个多项式 g(x) g ( x )
g(x)=n1i=0fi(x)fni1(x) g ( x ) = ∑ i = 0 n − 1 f i ( x ) ∗ f n − i − 1 ( x )

输入格式
第一行一个正整数 n
第二行 n 个整数,表示a0,a1…an−1
输出格式
假设 g(x)=n1i=0bixi g ( x ) = ∑ i = 0 n − 1 b i x i
第一行输出 n 个整数,表示 b0,b1..bn−1 对 998244353 取模的值

样例1
样例输入
3
1 2 3
样例输出
16 48 72
样例2
见下载文件


暴力 n2logn n 2 l o g n 就不讲了,按照题意做
这种题看一眼头就炸了是吗
(其实这题蛮暴力的,大力推导,代码也好写
我们假设 gi g i g(x) g ( x ) xi x i 的系数
fi f i 同理
经过推导我们可以得到
gd=n1i=0dj=0fi+j(i+j)!j! g d = ∑ i = 0 n − 1 ∑ j = 0 d f i + j ∗ ( i + j ) ! j !
fn1i+dj(n1i+dj)!(dj)! ∗ f n − 1 − i + d − j ∗ ( n − 1 − i + d − j ) ! ( d − j ) !
相当于是枚举每一位,原函数中每一阶暴力展开
fi=fii! f i = f i ∗ i !
化为
gd=i=0n1j=0dfi+j1j!fn1i+dj1(dj)! g d = ∑ i = 0 n − 1 ∑ j = 0 d f i + j ∗ 1 j ! ∗ f n − 1 − i + d − j ∗ 1 ( d − j ) !
大部分项只和 i+j i + j 有关,只有阶乘单单和j有关,这个形式我们又是可以推导成另一个式子
那么我们用 i i 表示原来的i+j
gd=n1+di=0fifn1+didj=01(dj)!j![j<=i][dj<=n1+di] g d = ∑ i = 0 n − 1 + d f i ∗ f n − 1 + d − i ∗ ∑ j = 0 d 1 ( d − j ) ! j ! ∗ [ j <= i ] ∗ [ d − j <= n − 1 + d − i ]
棘手的是后面的部分
观察发现
i<j i < j (即条件一不满足)
那么 i<d i < d , n1+di>=n n − 1 + d − i >= n fn1+di=0 f n − 1 + d − i = 0 ,会被自动过滤
dj>n1+di d − j > n − 1 + d − i i>n1+j>=n1 i > n − 1 + j >= n − 1 fi=0 f i = 0 ,也会被过滤
那现在我们只要求
gd=n1+di=0fifn1+didj=01(dj)!j! g d = ∑ i = 0 n − 1 + d f i ∗ f n − 1 + d − i ∗ ∑ j = 0 d 1 ( d − j ) ! j !
后面那个求和就等于 2dd! 2 d d ! (组合数学)
前面的部分可以用 FFT F F T 解决


#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rep(i,j,k) for(int i = j;i <= k;++i)
#ifdef M_pi
const double pi = M_pi;
#else
const double pi = acos(-1.0);
#endif
const int g = 3;
int N ;
const int p = 998244353;
const int NUM = 22;
int n;
ll f[300010] , jc[300010];
ll a[300010] , b[300010];
ll ans[300010];
int r[300010];
int flen;

int read()
{
    int sum = 0;char c = getchar();bool flag = true;
    while( c < '0' || c > '9' ) {if(c == '-') flag = false;c = getchar();}
    while( c >= '0' && c <= '9' ) sum = sum * 10 + c - 48 , c = getchar();
    if(flag)  return sum;
     else return -sum;
}
ll mul(ll a, ll b){return (ll)(a*b)%p;}
ll power(ll a, ll b)  
{  
    ll ans = 1;  
    a %= p;  
    while(b)  {  
        if(b & 1)    
            ans = ans * a % p, 
            b--;  
        b >>= 1;  
        a = a * a % p;  
    } 
    return ans%p;  
}  
void ntt(ll *a ,int f){
    for(int i = 0; i < flen; ++i)
        if(i < r[i]) swap(a[i], a[r[i]]);
    int cnt = 0;
    for(int len = 2;len <= flen;len *= 2){
        ll wn = power( g , (p - 1) / len );
        if(f == -1) wn = power(wn , p-2);
        for(int k = 0;k <= flen / len - 1;++k){
            int st = k * len;
            ll w = 1;
            for(int i = 0;i < len / 2;++i){
                ll x = a[st + i] % p,
                    y = (a[st + i + len / 2] % p) * w % p;
                a[st + i] = (x + y + p) % p;
                a[st + i + len / 2] = (x - y + p) % p;
                w = w * wn % p;
            }
        }
    } 
    if(f == -1){
        int inv = power(N , p-2);
        for(int i = 0;i < N ;++i)
          a[i] = 1ll * a[i] * inv % p;
    }
    return;
}   
void solve_NTT(int n,int m)
{
    flen = 1;
    while( flen < (n + m + 1)) flen *= 2;
    N = flen;
    for(int i = n + 1;i < flen;++i) a[i] = 0;
    for(int i = m + 1;i < flen;++i) b[i] = 0;  
    int l = log2(flen);
    for(int i = 0;i < flen;++i){
        r[i] = r[i>>1]>>1;
        if(i & 1) r[i] |= 1<<(l-1);
    }
    ntt(a,1);
    ntt(b,1);
    for(int i = 0;i < flen;++i) a[i] = mul(a[i] , b[i]);
    ntt(a,-1);
    return;
}
void putout(ll x){
    if(x >= 10) putout(x / 10);
    putchar(x % 10 + '0');
}
void init()
{
    n = read();
    rep(i,0,n-1) f[i] = read();
    jc[0] = 1;
    rep(i,1,n) jc[i] = jc[i-1] * i % p;
    rep(i,0,n-1) f[i] = f[i] * jc[i] % p;
    rep(i,0,n-1) a[i] = b[i] = f[i];
    solve_NTT(n-1,n-1);
    ll now = 1;
    rep(i,0,n-1) jc[i] = power(jc[i],p-2); 
    rep(i,0,n-1) 
        putout(((a[i+n-1] * now)%p * jc[i])%p),
        putchar(' '),
        now = now * 2 % p;
    return;
}
int main()
{
    init();
    return 0;
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值