zoukankan      html  css  js  c++  java
  • Solution -「多校联训」查拉图斯特拉如是说

    (mathcal{Description})

      Link.

      给定 (n)(m) 次多项式 (f(x)),求

    [sum_{i=0}^ninom{n}{i}f(i)mod998244353 ]

      (mle10^5)(mle nle 10^9)

    (mathcal{Solution})

      推式子叭~

    [egin{aligned} sum_{i=0}^ninom{n}{i}f(i)&=sum_{i=0}^ma_isum_{j=0}^ninom{n}{i}j^i\ &=sum_{i=0}^ma_ii![x^i]left(sum_{j=0}^{+infty}frac{x^j}{j!}sum_{k=0}^ninom{n}{k}k^j ight)\ &=sum_{i=0}^ma_ii![x^i]left(sum_{k=0}^ninom{n}{k}e^{kx} ight)\ &=sum_{i=0}^ma_ii![x^i](e^x+1)^n end{aligned} ]

    多项式全家桶算出 ((e^x+1)^n) 即可,复杂度 (mathcal O(mlog m))

    (mathcal{Code})

    /*~Rainybunny~*/
    
    #include <cmath>
    #include <cstdio>
    #include <algorithm>
    
    #define rep( i, l, r ) for ( int i = l, rpbound##i = r; i <= rpbound##i; ++i )
    #define per( i, r, l ) for ( int i = r, rpbound##i = l; i >= rpbound##i; --i )
    
    const int MOD = 998244353, MAXL = 1 << 18, MAXM = 1e5, INV2 = MOD + 1 >> 1;
    int n, m, c[MAXM + 5], fac[MAXL + 5], ifac[MAXL + 5];
    int F[MAXL + 5], G[MAXL + 5];
    
    inline int sub( int a, const int b ) { return ( a -= b ) < 0 ? a + MOD : a; }
    inline int mul( const long long a, const int b ) { return int( a * b % MOD ); }
    inline int add( int a, const int b ) { return ( a += b ) < MOD ? a : a - MOD; }
    inline int mpow( int a, int b ) {
        int ret = 1;
        for ( ; b; a = mul( a, a ), b >>= 1 ) ret = mul( ret, b & 1 ? a : 1 );
        return ret;
    }
    
    inline void init( const int len ) {
        fac[0] = 1;
        rep ( i, 1, len ) fac[i] = mul( i, fac[i - 1] );
        ifac[len] = mpow( fac[len], MOD - 2 );
        per ( i, len - 1, 0 ) ifac[i] = mul( i + 1, ifac[i + 1] );
    }
    
    namespace PolyOper {
    
    const int MG = 3;
    int inv[MAXL + 5], omega[19][MAXL + 5];
    
    inline void init() {
        inv[1] = 1;
        rep ( i, 2, MAXL ) inv[i] = mul( MOD - MOD / i, inv[MOD % i] );
        rep ( i, 0, 18 ) {
            int* oi = omega[i];
            oi[0] = 1;
            int& o1 = oi[1] = mpow ( MG,  MOD - 1 >> i >> 1 );
            rep ( j, 2, ( 1 << i ) - 1 ) oi[j] = mul( oi[j - 1], o1 );
        }
    }
    
    inline void ntt( const int n, int* u, const int type ) {
        static int rev[MAXL + 5];
        int lgn = 1;
        for ( ; 1 << lgn < n; ++lgn );
        rep ( i, 1, n - 1 ) rev[i] = rev[i >> 1] >> 1 | ( i & 1 ) << lgn >> 1;
        rep ( i, 1, n - 1 ) if ( i < rev[i] ) {
            u[i] ^= u[rev[i]] ^= u[i] ^= u[rev[i]];
        }
        for ( int i = 0, stp = 1; stp < n; ++i, stp <<= 1 ) {
            const int* oi = omega[i];
            for ( int j = 0; j < n; j += stp << 1 ) {
                rep ( k, j, j + stp - 1 ) {
                    int ev = u[k], ov = mul( oi[k - j], u[k + stp] );
                    u[k] = add( ev, ov ), u[k + stp] = sub( ev, ov );
                }
            }
        }
        if ( type == -1 ) {
            for ( int invn = MOD - ( MOD - 1 ) / n, i = 0; i < n; ++i ) {
                u[i] = mul( u[i], invn );
            }
            std::reverse( u + 1, u + n );
        }
    }
    
    inline void polyDir ( const int n, const int* u, int* w ) {
        rep ( i, 1, n - 1 ) w[i - 1] = mul( i, u[i] );
        w[n - 1] = 0;
    }
    
    inline void polyInt( const int n, const int* u, int* w ) {
        per ( i, n - 1, 0 ) w[i + 1] = mul( inv[i + 1], u[i] );
        w[0] = 0;
    }
    
    inline void polyInv( const int n, const int* u, int* w ) {
        static int tmp[2][MAXL + 5];
        if ( n == 1 ) return void( w[0] = mpow( u[0], MOD - 2 ) );
        polyInv( n >> 1, u, w );
        rep ( i, 0, n - 1 ) tmp[0][i] = u[i], tmp[1][i] = w[i];
        ntt( n << 1, tmp[0], 1 ), ntt( n << 1, tmp[1], 1 );
        rep ( i, 0, ( n << 1 ) - 1 ) {
            tmp[0][i] = mul( mul( tmp[0][i], tmp[1][i] ), tmp[1][i] );
        }
        ntt( n << 1, tmp[0], -1 );
        rep ( i, 0, n - 1 ) w[i] = sub( mul( 2, w[i] ), tmp[0][i] );
        rep ( i, 0, ( n << 1 ) - 1 ) tmp[0][i] = tmp[1][i] = 0;
    }
    
    inline void polyLn( const int n, const int* u, int* w ) {
        static int tmp[2][MAXL + 5];
        polyDir( n, u, tmp[0] ), polyInv( n, u, tmp[1] );
        ntt( n << 1, tmp[0], 1 ), ntt( n << 1, tmp[1], 1 );
        rep ( i, 0, ( n << 1 ) - 1 ) tmp[0][i] = mul( tmp[0][i], tmp[1][i] );
        ntt( n << 1, tmp[0], -1 ), polyInt( n << 1, tmp[0], w );
        rep ( i, 0, ( n << 1 ) - 1 ) tmp[0][i] = tmp[1][i] = 0;
    }
    
    inline void polyExp ( const int n, const int* u, int* w ) {
        static int tmp[MAXL + 5];
        if ( n == 1 ) return void( w[0] = 1 );
        polyExp( n >> 1, u, w ), polyLn( n, w, tmp );
        tmp[0] = sub( add( u[0], 1 ), tmp[0] );
        rep ( i, 1, n - 1 ) tmp[i] = sub( u[i], tmp[i] );
        ntt( n << 1, tmp, 1 ), ntt( n << 1, w, 1 );
        rep ( i, 0, ( n << 1 ) - 1 ) w[i] = mul( w[i], tmp[i] );
        ntt( n << 1, w, -1 );
        rep ( i, n, ( n << 1 ) - 1 ) w[i] = tmp[i] = 0;
    }
    
    } // namespace PolyOper.
    
    int main () {
        freopen( "number.in", "r", stdin );
        freopen( "number.out", "w", stdout );
    
        PolyOper::init();
        scanf( "%d %d", &n, &m ), ++m;
        rep ( i, 0, m - 1 ) scanf( "%d", &c[i] );
        
        int len = 1;
        for ( ; len < m; len <<= 1 );
        init( len ), F[0] = 1;
        rep ( i, 1, len - 1 ) F[i] = mul( ifac[i], INV2 );
        
        PolyOper::polyLn( len, F, G );
        rep ( i, 0, len - 1 ) G[i] = mul( G[i], n ), F[i] = 0;
        PolyOper::polyExp( len, G, F );
    
        int ans = 0;
        rep ( i, 0, m - 1 ) ans = add( ans, mul( c[i], mul( fac[i], F[i] ) ) );
        printf( "%d
    ", mul( ans, mpow( 2, n ) ) );
        return 0;
    }
    
    
  • 相关阅读:
    题解 P1030 【求先序排列】
    行列式及其打开方式
    题解 P2580 【于是他错误的点名开始了】
    题解 P1130 【红牌】
    题解 P5239 【回忆京都】
    题解 P1184 【高手之在一起】
    【笔记】自学ST表笔记
    题解 P1208 【[USACO1.3]混合牛奶 Mixing Milk】
    树状数组自学笔记
    EBS R12.2系统logo的修改
  • 原文地址:https://www.cnblogs.com/rainybunny/p/14991281.html
Copyright © 2011-2022 走看看