Live2D

Solution -「ABC 213H」Stroll

Description

  Link.

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

  n,m10T4×104

Solution

  令 fi(x)=j0fi,jxj,从 1 出发到 i 的所有路径边权积的和,那么对于一条边 e(u,v),设其边权为 ge,它会为 f 提供转移:

fu,ifu,i+d=1T[xd]gefv,id

fu(x)fu(x)+ge(x)fv(x)

所以整体做一个分治 FFT 就能求出所有 f。复杂度 O(mTlog2T)

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;
}

posted @   Rainybunny  阅读(171)  评论(6编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示