"JSOI2019" neural network (inclusion and exclusion) (Combinatorics) (generating function) (tree DP)

Portal

Meaning of the questions: to m m tree, the tree is complete between FIG ask Hamilton Cycle Number


We take into account the final Hamiltonian circuit must have a section of the tree to get the chain to string together

Each tree corresponding to the tree split into several pieces of chain, the number is not limited to the size limitation, all stitching together adjacent not required from the same tree

We can tree d p dp obtained into a tree j j number of program chains, where the direction of belt

Next, let's not consider the ring, only consider the sequence of problems have converted m m colors balls, each with a number of requirements, without seeking the final stitching together the same number of adjacent color

We handpicked for each color it has at least the same number to be adjacent to the inclusion-exclusion, we will merge the adjacent color stitching and other
direct construction of each color E G F EGF , After the size of the combined enumeration

F i ( x ) = j = 1 n f [ i ] [ j ] j ! k = 1 j ( j 1 k 1 ) ( 1 ) j k x k k ! F_i(x)=\sum_{j=1}^nf[i][j]*j!\sum_{k=1}^{j}\binom{j-1}{k-1}(-1)^{j-k}\frac{x^k}{k!}

Consider the case of how to do the ring, the first force is the chain 1 is located, there are E G F EGF
F 1 ( x ) = j = 1 n f [ i ] [ j ] ( j 1 ) ! k = 1 j ( j 1 k 1 ) ( 1 ) j k x k 1 ( k 1 ) ! F_1(x)=\sum_{j=1}^nf[i][j](j-1)!\sum_{k=1}^j\binom{j-1}{k-1}(-1)^{j-k}\frac{x^{k-1}}{(k-1)!}

Minus the illegal situation, the last Imperial on the first tree, then to subtract:
F 1 ( x ) = j = 1 n f [ i ] [ j ] ( j 1 ) ! k = 2 j ( j 1 k 1 ) ( 1 ) j k x k 2 ( k 2 ) ! F_1'(x)=\sum_{j=1}^nf[i][j](j-1)!\sum_{k=2}^j\binom{j-1}{k-1}(-1)^{j-k}\frac{x^{k-2}}{(k-2)!}

Violence ride up on it

Tree-DP, consider f [ i ] [ j ] [ 0 / 1 / 2 ] f[i][j][0/1/2] represented by i to j is selected from the strands of the program number
0 represents i i isolated, 1 1 represents i matches downwardly, 2 2 represents one path down through the upwardly i i
This is done in order to process 2 2 coefficients

#include<bits/stdc++.h>
#define cs const
using namespace std;
cs int N = 5e3 + 5;
int read(){
	int cnt = 0, f = 1; char ch = 0;
	while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1; }
	while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
	return cnt * f;
}
int first[N], nxt[N << 1], to[N << 1], tot;
void adde(int x, int y){ nxt[++tot] = first[x], first[x] = tot, to[tot] = y; }
cs int Mod = 998244353, inv2 = (Mod+1)>>1;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b; }
int dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
int mul(int a, int b){ return 1ll * a * b % Mod; }
void Add(int &a, int b){ a = add(a, b); }
void Mul(int &a, int b){ a = mul(a, b); }
int ksm(int a, int b){ int ans = 1; for(;b;b>>=1,a=mul(a,a)) if(b&1) ans = mul(ans, a); return ans; }
int fac[N], ifac[N]; int T, n, node;
int dp[N][N][3], sz[N];
int C(int n, int m){ if(n<0||m<0||n<m) return 0; return mul(fac[n], mul(ifac[m], ifac[n-m])); }
void prework(){
	fac[0] = fac[1] = ifac[0] = ifac[1] = 1;
	for(int i = 2; i <= N-5; i++) fac[i] = mul(fac[i-1], i);
	ifac[N-5] = ksm(fac[N-5], Mod-2);
	for(int i = N-6; i >= 2; i--) ifac[i] = mul(ifac[i+1], i+1);
}
void Merge(int u, int v){
	int a = sz[u], b = sz[v]; sz[u] += sz[v];
	static int tp[N][3]; memset(tp, 0, sizeof(int) * (a+b+1) * 3);
	for(int i = 1; i <= b; i++){
		int all = add(dp[v][i][0], add(dp[v][i][1], dp[v][i][2]));
		for(int j = 1; j <= a; j++){
			Add(tp[i + j][0], mul(dp[u][j][0], all));
			Add(tp[i + j][1], mul(dp[u][j][1], all));
			Add(tp[i + j][2], mul(dp[u][j][2], all));
			Add(tp[i + j - 1][1], mul(dp[u][j][0], add(dp[v][i][1], mul(dp[v][i][0], 2))));
			Add(tp[i + j - 1][2], mul(dp[u][j][1], add(dp[v][i][0], mul(dp[v][i][1], inv2))));
		} 
	} memcpy(dp[u], tp, sizeof(int) * (a+b+1) * 3);
}
void dfs(int u, int fa){
	memset(dp[u], 0, sizeof(int) * (sz[u] + 1) * 3); sz[u] = dp[u][1][0] = 1; 
	for(int i = first[u]; i; i = nxt[i]) if(to[i]^fa) dfs(to[i], u), Merge(u, to[i]);
}
int ans[N], G[N];
void PolyMul(int a, int b){ 
	static int tmp[N + N];
	memset(tmp, 0, sizeof(int) * (a+b-1));
	for(int i = 0; i < a; i++) for(int j = 0; j < b; j++)
	Add(tmp[i + j], mul(ans[i], G[j]));
	memcpy(ans, tmp, sizeof(int) * (a+b-1));
}
int main(){
	T = read(); ans[0] = 1; prework();
	while(T--){
		int k = read(); tot = 0; memset(first, 0, sizeof(int) * (k+1));
		for(int i = 1; i < k; i++){ int x = read(), y = read(); adde(x, y); adde(y, x); }
		dfs(1, 0); static int ct[N];
		for(int i = 1; i <= k; i++)
		ct[i] = mul(T==0?fac[i-1]:fac[i], add(dp[1][i][0], add(dp[1][i][1], dp[1][i][2])));
		for(int i = 1; i <= k; i++){
			int coef = 0;
			for(int j = i; j <= k; j++){
				int vl = mul(ct[j], C(j-1, i-1));
				(j-i)&1 ? Add(coef, Mod-vl) : Add(coef, vl);
			} if(T == 0){
				G[i-1] = coef; if(i > 1) Add(G[i-2], Mod-coef);
			} else G[i] = coef;
		} if(T == 0) G[k] = 0; else G[0] = 0;
		for(int i = 0; i <= k; i++) Mul(G[i], ifac[i]);
		PolyMul(node+1, k+1); node += k;
	} int sum = 0;
	for(int i = 0; i <= node; i++) Add(sum, mul(fac[i], ans[i]));
	cout << sum; return 0;
}
Published 610 original articles · won praise 94 · views 50000 +

Guess you like

Origin blog.csdn.net/sslz_fsy/article/details/103501375