[CTS2019] Функция Pearl-генератора + биномиальная инверсия

вопросы для лица

  LOJ3120

Решимость

  Рассмотрим, как определить, удовлетворяет ли последовательность условию. Пусть $ c_i $ представляет число вхождений числа $ i $, затем: $$ \ sum_ {i = 1} ^ D \ left \ lfloor \ frac {c_i} {2} \ right \ rfloor \ geqslant m \\ \ sum_ {i = 1} ^ D \ frac {c_i- (c_i \% 2)} {2} \ geqslant m \\ n- \ sum_ {i = 1} ^ D (c_i \% 2) \ geqslant 2m \\ \ sum_ {i = 1} ^ D (c_i \% 2) \ leqslant n-2m $$

  Когда $ n-2m <0 $, выведите $ 0 $, когда $ n-2m \ geqslant D $, выведите $ D ^ n $

  Пусть $ g_i $ означает, что ровно число вхождений $ i $ нечетно, а $ f_i $ означает, что хотя бы $ i $ вхождений нечетно, а $ f_i = \ sum_ {j = i} \ binom {j} { я} g_j $

  Если мы найдем $ f $, то сможем найти $ g $ путем биномиальной инверсии, поэтому теперь нам нужно найти способ найти $ f $

  Рассмотрим создание функций, пусть $ A (x) = \ sum_ {i = 0} ^ {\ infty} [i \% 2 == 1] x ^ i = \ frac {e ^ xe ^ {-x}} {2 } $, $ B (x) = \ sum_ {i = 0} ^ {\ infty} x ^ i = e ^ x $

  钦 定 有 $ I $ 个数 出现 奇 数次, 剩下 的 数 出现 任意 次数, 则 有: $$ \ {начать выравнивание *} f_i & = \ БИНОМ {D} {г} п [х ^ п] А ^ И.Б. ^ {Di} \\ & = \ БИНОМ {D} {г} п [х ^ п] (\ гидроразрыва {е ^ х ^ {- х}} {2})! ^ т ^ {(Di) х} \ \ & = \ гидроразрыва {D!} {я! (Ди)!} п! * \ гидроразрыва {1} {2 ^ я} [х ^ п] \ sum_ {J = 0} ^ я \ БИНОМ {я} { J} (- 1) ^ {IJ} е ^ {JX} е ^ {-! (Ij) х} е ^ {(Di) х} \\ & = \ гидроразрыва {D} {п я (Di) ! 2 ^ я} * [х ^ п] \ sum_ {J = 0} ^ я \ БИНОМ {я} {J} (- 1) ^ {IJ} е ^ {(D-2i + 2j) х} \\ & = \ гидроразрыва {D п!} {я (Di) 2 ^ я!} \ sum_ {j = 0} ^ я \ гидроразрыва {я!} * {j (Ij)!} (- 1) ^ {IJ} * \ гидроразрыва {(D-2i + 2j) ^ п} {п!} \\ & = \ гидроразрыва {D!} {(Di)! 2 ^ я} \ sum_ {j = 0} ^ я \ гидроразрыва {(- 1) ^ {IJ} (D-2i + 2j) ^ п} {! (Ij)} * \ гидроразрыва {1} {! J} \ конец {выравнивание *} $$

  Свернуть, чтобы найти $ f $

  然后 二项式 反演: $$ \ {начать выравнивание *} g_i & = \ sum_ {J = я} ^ D (-1) ^ {ц} \ БИНОМ {J} {} я f_j \\ & = \ гидроразрыва { 1} {г} \ sum_ {j = я} ^ D \ гидроразрыва {! (- 1) ^ {ц}!} {(ц)} * J * f_j \ конец {выравнивание *} $$

  Окончательный ответ: $ Ans = \ sum_ {i = 0} ^ {n-2m} g_i $$

  $ O (D \ log D) $

 Код:

#include <cstdio> 
#include <iostream> 
#include <алгоритм> 
#include <cstring>
 с использованием  пространства имен std; 
typedef long  long ll;
const  int maxn = 200005 , mod = 998244353 , g = 3 ; 

int add ( int x, int y) 
{ 
    вернуть x + y <mod? х + у: х + у - мод; 
} 

int rdc ( int x, int y) 
{ 
    return x - y < 0? х - у + мод: х - у; 
} 

ll qpow (ll x, int y) 
{ 
    ll ret = 1 ;
    while (y) 
    { 
        if (y & 1 ) 
            ret = ret * x% mod; 
        х = х * х% мод; 
        у >> = 1 ; 
    } 
    return ret; 
} 

int D, n, m;
int lim, bit, rev [maxn << 1 ]; 
ll fac [maxn], fnv [maxn]; 
ll ginv, f [maxn << 1 ], A [maxn << 1], B [maxn << 1 ]; 

void init () 
{ 
    ginv = qpow (g, mod - 2 ); 
    fac [ 0 ] = 1 ;
    for ( int i = 1 ; i <= D; ++ i) 
        fac [i] = fac [i- 1 ] * i% mod; 
    fnv [D] = qpow (fac [D], mod - 2 );
    для ( int i = D - 1 ; i> = 0 ; - i) 
        fnv [i] = fnv [i + 1 ] * (i + 1 )%мод; 
} 

void NTT_init ( int x) 
{ 
    lim = 1 ; 
    бит = 0 ;
    while (lim <= x) 
    { 
        lim << = 1 ;
        ++ бит; 
    } 
    for ( int i = 1 ; i <lim; ++ i) 
        rev [i] = (rev [i >> 1 ] >> 1 ) | ((i & 1 ) << (бит - 1 )); 
} 

void NTT (ll * x, int  y)
{
    for ( int i = 1 ; i <lim; ++ i)
         if (i < rev [i]) 
            swap (x [i], x [rev [i]]); 
    ll wn, w, u, v; 
    for ( int i = 1 ; i <lim; i << = 1 ) 
    { 
        wn = qpow ((y == 1 )? g: ginv, (mod - 1 ) / (i << 1 ));
        для ( int j = 0 ; j <lim; j + = (i << 1 )) 
        { 
            w = 1 ;
            для( int k = 0 ; k <i; ++ k) 
            { 
                u = x [j + k]; 
                v = x [j + k + i] * w% mod; 
                x [j + k] = add (u, v); 
                x [j + k + i] = rdc (u, v); 
                w = w * wn% mod; 
            } 
        } 
    } 
    if (y == - 1 ) 
    { 
        ll linv = qpow (lim, mod - 2 );
        для ( int i = 0 ; i <lim; ++ i) 
            x [i] = x [i] * linv% mod; 
    } 
} 

int main () 
{ 
    scanf ( " % d% d% d " , & D, & n, & m);
    if (n - 2 * m < 0 ) 
    { 
        printf ( " 0 " );
        вернуть  0 ; 
    } 
    if (n - 2 * m> = D) 
    { 
        printf ( " % lld " , qpow (D, n));
        вернуть  0 ; 
    } 
    init ();
    для ( int i = 0 ; i <= D; ++ i) 
    { 
        A [i] = qpow (rdc (D, 2 * i), n) * fnv [i]% mod; 
        A [i] = ((i & 1 )? Rdc ( 0 , A [i]): A [i]); 
        B [i] = fnv [i]; 
    } 
    NTT_init (D << 1 ); 
    NTT (A, 1 ); 
    NTT (B, 1 );
    для ( int i = 0 ; i <lim; ++ i) 
        A [i] = A [i] * B [i]% mod;
    NTT (A, - 1 );
    для ( int i = 0 ; i <= D; ++ i) 
        A [i] = ((A [i] * fac [D]% mod) * qpow (qpow ( 2 , i), mod - 2 )% mod) * fnv [Di]% mod;
    для ( int i = D + 1 ; i <lim; ++ i) 
        A [i] = 0 ;
    for ( int i = 0 ; i <= D; ++ i) 
    { 
        A [i] = A [i] * fac [i]% mod; 
        f [D 1-i] = ((i & )? rdc ( 0 , fnv [i]): fnv [i]); 
    } 
    NTT (A, 1 ); 
    NTT (f, 1 );
    for ( int i = 0 ; i <lim; ++ i) 
        f [i] = f [i] * A [i]% mod; 
    NTT (f, - 1 );
    int ans = 0 ;
    for ( int i = 0 ; i <= n - 2 * m; ++ i) 
        ans = add (ans, f [D + i] * fnv [i]% mod); 
    printf ( " % d " , ans);
     вернуть  0 ; 
}
Посмотреть код

рекомендация

отwww.cnblogs.com/Joker-Yza/p/12676806.html