zoukankan      html  css  js  c++  java
  • Solution -「ABC 213H」Stroll

    (mathcal{Description})

      Link.

      给定一个含 (n) 个结点 (m) 条边的简单无向图,每条边的边权是一个常数项为 (0)(T) 次多项式,求所有从 (1) 结点出发回到 (1) 结点的环路中,边权之积的 (T) 次项系数和。

      (n,mle10)(Tle4 imes10^4)

    (mathcal{Solution})

      令 (f_i(x)=sum_{jge0}f_{i,j}x^j),从 (1) 出发到 (i) 的所有路径边权积的和,那么对于一条边 (e(u,v)),设其边权为 (g_e),它会为 (f) 提供转移:

    [f_{u,i}leftarrow f_{u,i}+sum_{d=1}^T [x^d]g_ef_{v,i-d} ]

    [f_u(x)leftarrow f_u(x)+g_e(x)f_v(x) ]

    所以整体做一个分治 FFT 就能求出所有 (f)。复杂度 (mathcal O(mTlog^2T))

    (mathcal{Code})

    /*~Rainybunny~*/
    
    #include <cstdio>
    #include <vector>
    #include <cassert>
    #include <algorithm>
    
    #define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
    #define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i )
    
    typedef std::vector<int> Poly;
    
    const int MAXN = 10, MAXL = 1 << 17, MOD = 998244353;
    int N, M, T, eu[MAXN + 5], ev[MAXN + 5];
    Poly E[MAXN + 5], F[MAXN + 5];
    
    inline void subeq( int& a, const int b ) { ( a -= b ) < 0 && ( a += MOD ); }
    inline int sub( int a, const int b ) { return ( a -= b ) < 0 ? a + MOD : a; }
    inline int add( int a, const int b ) { return ( a += b ) < MOD ? a : a - MOD; }
    inline void addeq( int& a, const int b ) { ( a += b ) >= MOD && ( a -= MOD ); }
    inline int mul( const int a, const int b ) { return int( 1ll * a * b % 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;
    }
    
    namespace PolyOper {
    
    const int MG = 3;
    int omega[17][MAXL];
    
    inline void init() {
        rep ( i, 0, 16 ) {
            int* oi = omega[i];
            oi[0] = 1, oi[1] = mpow( MG, MOD - 1 >> i >> 1 );
            rep ( j, 2, ( 1 << i ) - 1 ) oi[j] = mul( oi[j - 1], oi[1] );
        }
    }
    
    inline void ntt( Poly& u, const int type ) {
        static int rev[MAXL]; rev[0] = 0;
        int n = int( u.size() ), 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 ) {
            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 ) {
            int ivn = MOD - ( MOD - 1 ) / n;
            rep ( i, 0, n - 1 ) u[i] = mul( u[i], ivn );
            std::reverse( u.begin() + 1, u.end() );
        }
    }
    
    } // namespace PolyOper.
    
    inline Poly operator * ( Poly u, Poly v ) {
    	assert( u.size() && v.size() );
    	int su = int( u.size() ), sv = int( v.size() ), len = 1;
    	for ( ; len < su + sv - 1; len <<= 1 );
    	
    	u.resize( len ), v.resize( len );
    	PolyOper::ntt( u, 1 ), PolyOper::ntt( v, 1 );
    	rep ( i, 0, len - 1 ) u[i] = mul( u[i], v[i] );
    	PolyOper::ntt( u, -1 );
    	
    	return u.resize( su + sv - 1 ), u;
    }
    
    inline void solve( const int l, const int r ) {
    	if ( l == r ) return ;
    	int mid = l + r >> 1;
    	
    	solve( l, mid );
    	
    	rep ( i, 1, M ) {
    		int u = eu[i], v = ev[i];
    		static Poly A, B, R;
    		
    		A = { F[u].begin() + l, F[u].begin() + mid + 1 };
    		B = { E[i].begin() + 1, E[i].begin() + r - l + 1 };
    		R = A * B;
    		rep ( j, mid + 1, r ) addeq( F[v][j], R[j - l - 1] );
    		
    		A = { F[v].begin() + l, F[v].begin() + mid + 1 };
    		B = { E[i].begin() + 1, E[i].begin() + r - l + 1 };
    		R = A * B;
    		rep ( j, mid + 1, r ) addeq( F[u][j], R[j - l - 1] );
    	}
    	
    	solve( mid + 1, r );
    }
    
    int main() {
    	PolyOper::init();
    	scanf( "%d %d %d", &N, &M, &T );
    	rep ( i, 1, M ) {
    		scanf( "%d %d", &eu[i], &ev[i] ), --eu[i], --ev[i];
    		E[i].resize( T + 1 );
    		rep ( j, 1, T ) scanf( "%d", &E[i][j] );
    	}
    	
    	rep ( i, 0, N - 1 ) F[i].resize( T + 1 );
    	F[0][0] = 1, solve( 0, T );
    	printf( "%d
    ", F[0][T] );
    	return 0;
    }
    
    
  • 相关阅读:
    关于OPENSSL的EVP函数的使用
    在docker下面安装Nginx PHP mysql let's encrypt
    【转】如何统计网站(如个人博客)访问量
    CoolEdit对比两段音频文件:将两段音频文件放在左右声道
    matlab常用的清空和关闭命令(清空变量区、清空命令行、清空图像等)
    TMS320F28335利用ePWM改变ADC采样频率(双通道)示例代码
    Matlab中rand、randn、randi、rands的区别以及用randn生成白噪声的示例
    Matlab中find()寻找函数的常见用法
    【转】 博客园自定义样式修改网页icon图标
    UltraEdit 高亮文档中同名变量
  • 原文地址:https://www.cnblogs.com/rainybunny/p/15118348.html
Copyright © 2011-2022 走看看