Solution -「ABC 213H」Stroll
阿新 • • 發佈:2021-08-09
\(\mathcal{Description}\)
Link.
給定一個含 \(n\) 個結點 \(m\) 條邊的簡單無向圖,每條邊的邊權是一個常數項為 \(0\) 的 \(T\) 次多項式,求所有從 \(1\) 結點出發回到 \(1\) 結點的環路中,邊權之積的 \(T\) 次項係數和。
\(n,m\le10\),\(T\le4\times10^4\)。
\(\mathcal{Solution}\)
令 \(f_i(x)=\sum_{j\ge0}f_{i,j}x^j\),從 \(1\) 出發到 \(i\) 的所有路徑邊權積的和,那麼對於一條邊 \(e(u,v)\),設其邊權為 \(g_e\)
即
\[f_u(x)\leftarrow f_u(x)+g_e(x)f_v(x) \]所以整體做一個分治 FFT 就能求出所有 \(f\)。複雜度 \(\mathcal O(mT\log^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\n", F[0][T] ); return 0; }