首页 > 其他分享 >SError_ 是我蝶

SError_ 是我蝶

时间:2024-06-04 22:56:12浏览次数:13  
标签:我蝶 int back poly ++ push SError tmp2

做多项式把自己做成若只了。

[ABC303Ex] Constrained Tree Degree

给定一个长度为 \(K\) 的正整数序列 \(S\),求有多少个不同的树 \(T\) 使得:

  • \(T\) 中有 \(N\) 个节点。
  • 对于 \(T\) 中的任意一个节点 \(i\) 的度数 \(d_i\),有 \(d_i\in S\)。

无根树计数,考虑 Prufer 序列。

问题转化成,现在有 \(n - 2\) 个数,每个数都是 \([1, n]\) 的整数,且每个数出现的次数加上 \(1\) 一定要在 \(S\) 集合中。那我们先将 \(S\) 集合的所有数减一,之后对 \(S\) 集合的描述默认已经减去 \(1\) 了。

先对每个数出现次数计数,即取 \(n\) 个数和为 \(n - 2\) 的方案数,即:

\[\left[x^{n - 2}\right]\left(\sum x^{s_i}\right)^n \]

假设取的数分别是 \(\{a_1, \dots, a_n\}\),其中 \(a_i \in S\),那么会乘上一个多重排列,即:

\[\frac{(n - 2)!}{\prod a_i!} \]

那么 \((n - 2)!\) 与选择的数无关可以提出来,剩下的阶乘挂到上面的 \(x^{s_i}\) 下面去。

所以最后的式子是:

\[(n-2)! \times \left[x^{n - 2}\right]\left(\sum\frac{x^{s_i}}{s_i!}\right)^n \]

#include<iostream>
#include<fstream>
#include<algorithm>
#include<vector>
#define int long long
using namespace std;
namespace Poly{
	using poly = vector<int>;
	const int G = 3, P = 998244353;
	const int inv2 = 499122177;
	int Ksm(int u, int v){
		int ret = 1;
		while(v){
			if(v & 1) ret = 1ll * ret * u % P;
			u = 1ll * u * u % P, v >>= 1;
		}
		return ret;
	}
	int NTT(poly &A, int N){
		int d = N >> 1;
		poly trn;
		trn.push_back(0);
		trn.push_back(d);
		for(int w = 2; w <= N; w <<= 1){
			d >>= 1;
			for(int c = 0; c < w; c ++)
				trn.push_back(trn[c] | d);
		}
		for(int i = 1; i < N; i ++)
			if(trn[i] > i)
				swap(A[i], A[trn[i]]);
		for(int len = 2, M = 1; len <= N; M = len, len <<= 1){
			int W;
			W = Ksm(G, (P - 1) / len);
			for(int l = 0; l <= N - len + 1; l += len){
				auto w0 = 1;
				for(int nw = l; nw < l + M; nw ++){
					int x = A[nw], y = 1ll * w0 * A[nw + M] % P;
					A[nw] = (x + y) % P, A[nw + M] = (x - y + P) % P;
					w0 = 1ll * w0 * W % P;
				}
			}
		}
		return 0;
	}
	poly convolution(poly a, poly b){
		int n = a.size(), m = b.size();
		if(!n || !m)
			return {};
		int sm = n + m - 1;
		int k = 1;
		while(k < sm)
			k <<= 1;
		a.resize(k), b.resize(k);
		NTT(a, k);
		NTT(b, k);
		for(int i = 0; i < k; i ++)
			a[i] = 1ll * a[i] * b[i] % P;
		NTT(a, k);
		reverse(++ a.begin(), a.end());
		int invk = Ksm(k, P - 2);
		for(int i = 0; i < a.size(); i ++)
			a[i] = 1ll * a[i] * invk % P;
		a.resize(n + m - 1);
		return a;
	}
	poly polyInv(poly f){
		int n = f.size();
		int k = 1;
		while(k < n)
			k <<= 1;
		k <<= 1;
		poly g;
		f.resize(k);
		g.push_back(Ksm(f[0], P - 2));
		for(int len = 2; len <= k; len <<= 1){
			int M = len >> 1;
			poly tmp2, tmp1;
			for(int i = 0; i < M; i ++)
				tmp2.push_back(g[i]);
			for(int i = 0; i < M; i ++)
				tmp1.push_back(f[i]);
			tmp1.resize(len);
			tmp2 = convolution(tmp2, tmp2);
			tmp2 = convolution(tmp1, tmp2);
			for(int i = 0; i < M; i ++)
				g[i] = (2ll * g[i] % P + P - tmp2[i]) % P;
			for(int i = M; i < len; i ++)
				g.push_back((2ll * g[i] % P + P - tmp2[i]) % P);
		}
		g.resize(n);
		return g;
	}
	poly polyDev(poly f){
		poly g;
		int k = f.size();
		for(int i = 1; i < k; i ++)
			g.push_back(1ll * i * f[i] % P);
		g.resize(k - 1);
		return g;
	}
	poly polyInDev(poly f){
		poly g;
		int k = f.size();
		g.push_back(0);
		for(int i = 1; i < k; i ++)
			g.push_back(1ll * f[i - 1] * Ksm(i, P - 2) % P);
		return g;
	}
	poly polyLn(poly a){
		int n = a.size();
		poly b = a;
		a = polyDev(a);
		b = polyInv(b);
		a = convolution(a, b);
		a = polyInDev(a);
		a.resize(n);
		return a;
	}
	int polyOutput(poly a){
		for(int i = 0; i < a.size(); i ++)
			cout << a[i] << " ";
		cout << "\n";
		return 0;
	}
	poly polyExp(poly f){
		int n = f.size();
		int k = 1;
		while(k < n)
			k <<= 1;
		k <<= 1;
		poly g;
		f.resize(k);
		g.push_back(1);
		for(int len = 2; len <= k; len <<= 1){
			int M = len >> 1;
			poly tmp2;
			for(int i = 0; i < M; i ++)
				tmp2.push_back(g[i]);
			auto tmp3 = polyLn(tmp2);
			for(int i = 0; i < M; i ++)
				tmp3[i] = (((P - tmp3[i] + f[i]) % P) + P) % P;
			tmp3[0] ++;
			tmp3[0] %= P;
			tmp2 = convolution(tmp3, tmp2);
			for(int i = 0; i < M; i ++)
				g[i] = tmp2[i];
			for(int i = M; i < len; i ++)
				g.push_back(tmp2[i]);
		}
		g.resize(n);
		return g;
	}
	poly polyPow(poly a, int k){
		int n = a.size();
		int t = 0;
		for(int i = 0; i < n; i ++){
			if(a[t] != 0) break;
			t ++;
		}
		if(t == n) return a;
		int r = Ksm(a[t], P - 2);
		poly b;
		for(int i = t; i < n; i ++)
			b.push_back(1ll * a[i] * r % P);
		a.resize(t);
		int m = b.size();
		b = polyLn(b);
		for(int i = 0; i < m; i ++)
			b[i] = 1ll * b[i] * k % P;
		b = polyExp(b);
		for(int i = 0; i < m; i ++)
			a.push_back(b[i]);
		return a;
	}
}
namespace azus{
	using namespace Poly;
	int n, m;
	poly a;
	int jc[200005], inv[200005];
	int main(){
		cin >> n >> m;
		a.resize(n);
		jc[0] = inv[0] = 1;
		for(int i = 1; i <= n; i ++)
			jc[i] = jc[i - 1] * i % P;
		inv[n] = Ksm(jc[n], P - 2);
		for(int i = n - 1; i >= 1; i --)
			inv[i] = inv[i + 1] * (i + 1) % P;
		for(int i = 1, x; i <= m; i ++){
			cin >> x;
			x --;
			a[x] = inv[x];
		}
		if(!a[0]) return cout << 0, 0;
//		polyOutput(a);
		a = polyPow(a, n);
//		polyOutput(a);
		cout << a[n - 2] * jc[n - 2] % P;
		return 0;
	}
}
signed main(){
//	ios::sync_with_stdio(0);
//	cin.tie(0), cout.tie(0);
	int T = 1;
	while(T --) azus::main();
	return 0;
}

SError_ 薄纱我系列。

标签:我蝶,int,back,poly,++,push,SError,tmp2
From: https://www.cnblogs.com/AzusidNya/p/18231945

相关文章