gym103415A Math Ball

套路生成函数。

写出答案的式子,设 fi(x)=jcixj,不难得到答案为:

[xW]11xi=1nfi(x)

考虑求 fi(x)。看到指数上有 ci,想到用斯特林数展开:

fi(x)=j=0xjk=0ci{cik}(jk)k!

=k=0ci{cik}k!j=k(jk)xj

注意到后面的式子是组合数一列的生成函数,设其为 gk(x),乘上 11x 对其系数做前缀和,由组合数按列求和的公式可知: 11xgk(x)=1xgk+1(x),gk(x)=xk(1x)k+1。将每个 xk(1x)k+1 分母中的一个 1x 提到外面,可以将答案写为:

[xW]1(1x)n+1i=1nk=0ci{cik}k!(x1x)k

将后面的 x1x 看成一整个变量,后面的那坨东西是可以分治 NTT 快速计算的。设得到的多项式为 F(t),那么总答案可以写为:

[xW]kFkxk(1x)n+k+1

虽然 W 很大,但是 F 有值的项数非常少。我们枚举 F 的项,由牛顿二项式定理可知 [xWk]1(1x)n+k+1=(W+nn+k),处理下降幂即可通过。

#include <bits/stdc++.h>

using namespace std;

#define pi pair<int,int>
#define mp make_pair
#define poly vector<int>

typedef long long ll;

const int N = 3e5 + 5, mod = 998244353, G = 3, Gi = (mod + 1) / G;

const int add(int a, int b) { return (a + b) >= mod ? a + b - mod : a + b; }
const int sub(int a, int b) { return a < b ? a - b + mod : a - b; }
const int mul(int a, int b) { return (1ll * a * b) % mod; }

const int power(int a, int b) {
	int t = 1, y = a, k = b;
	while (k) {
		if (k & 1) t = mul(t, y);
		y = mul(y, y); k >>= 1;
	} return t;
}

inline int read() {
	register int s = 0, f = 1; register char ch = getchar();
	while (!isdigit(ch)) f = (ch == '-' ? -1 : 1), ch = getchar();
	while (isdigit(ch)) s = (s << 1) + (s << 3) + (ch & 15), ch = getchar();
	return s * f;
}

inline ll readll() {
	register ll s = 0, f = 1; register char ch = getchar();
	while (!isdigit(ch)) f = (ch == '-' ? -1 : 1), ch = getchar();
	while (isdigit(ch)) s = (s << 1) + (s << 3) + (ch & 15), ch = getchar();
	return s * f;
}

inline void FFT(int *a, int len, int typ) {
	for (register int i = 0, j = 0, k; i < len; ++i) {
		if (i < j) swap(a[i], a[j]);
		for (k = len >> 1; k & j; k >>= 1) j ^= k;
		j ^= k;
	}
	for (register int mid = 1; mid < len; mid <<= 1) {
		int wn = power(typ == 1 ? G : Gi, (mod - 1) / (mid << 1));
		for (register int j = 0; j < len; j += mid << 1) {
			int bas = 1;
			for (register int k = 0; k < mid; ++k, bas = mul(bas, wn)) {
				int x = a[j + k], y = ::mul(bas, a[j + mid + k]);
				a[j + k] = ::add(x, y);
				a[j + mid + k] = ::sub(x, y);
			}
		}
	}
	if (!typ) {
		const int iv = power(len, mod - 2);
		for (register int i = 0; i < len; ++i)
			a[i] = ::mul(a[i], iv);
	}
}

inline int max_(int a, int b) {
	return a > b ? a : b;
}

inline int min_(int a, int b) {
	return a < b ? a : b;
}

inline poly add(poly a, int b) {
	for (register int i = 0; i < a.size(); ++i) a[i] = ::add(a[i], b);
	return a;
}

inline poly sub(poly a, int b) {
	for (register int i = 0; i < a.size(); ++i) a[i] = ::sub(a[i], b);
	return a;
}

inline poly mul(poly a, int b) {
	for (register int i = 0; i < a.size(); ++i) a[i] = ::mul(a[i], b);
	return a;
}

inline poly div(poly a, int b) {
	b = ::power(b, mod - 2);
	for (register int i = 0; i < a.size(); ++i) a[i] = ::mul(a[i], b);
	return a;
}

inline poly add(poly a, poly b) {
	a.resize(max_(a.size(), b.size()));
	for (register int i = 0; i < b.size(); ++i) a[i] = ::add(a[i], b[i]);
	return a;
}

inline poly sub(poly a, poly b) {
	a.resize(max_(a.size(), b.size()));
	for (register int i = 0; i < b.size(); ++i) a[i] = ::sub(a[i], b[i]);
	return a;
}

inline poly mul(poly a, poly b) {
	int p = a.size() + b.size() - 1; int len = 1 << (int)ceil(log2(p));
	a.resize(len); b.resize(len);
	FFT(&a[0], len, 1); FFT(&b[0], len, 1);
	for (register int i = 0; i < len; ++i)
		a[i] = ::mul(a[i], b[i]);
	FFT(&a[0], len, 0); a.resize(p);
	return a;
}

int fac[N], ifac[N];

inline poly stir2R(int n) {
	poly a, b, c;
	for (int i = 0; i <= n; ++i) {
		a.push_back((1ll * power(i, n) * ifac[i]) % mod);
		b.push_back(ifac[i]); if (i & 1) b[i] = -b[i] + mod;
		if (b[i] >= mod) b[i] -= mod;
	} c = mul(a, b); c.resize(n + 1); return c;
}

inline int C(int n, int m) {
	if (n < m) return 0;
	return 1ll * fac[n] * (1ll * ifac[m] * ifac[n - m] % mod) % mod;
}

inline void init() {
	fac[0] = 1;
	for (register int i = 1; i < N; ++i) fac[i] = (1ll * i * fac[i - 1]) % mod;
	ifac[N - 1] = power(fac[N - 1], mod - 2);
	for (register int i = N - 2; ~i; --i) ifac[i] = (1ll * (i + 1) * ifac[i + 1]) % mod;
}

inline void otp(int x) {
	(x >= 10) ? otp(x / 10), putchar((x % 10) ^ 48) : putchar(x ^ 48);
}

int n, c[N], cnt[N], mx = 0;
ll W;
vector<poly> F;
poly g;

inline poly calc(int l, int r) {
	if (l == r) return F[l];
	if (l + 1 == r) return mul(F[l], F[r]);
	int mid = l + r >> 1;
	return mul(calc(l, mid), calc(mid + 1, r));
}

int main() {
	init();
	n = read(); W = readll();
	for (int i = 1; i <= n; ++i) ++cnt[c[i] = read()], mx = max(mx, c[i]);
	for (int i = 0; i <= mx; ++i) {
		if (!cnt[i]) continue;
		poly s = stir2R(i);
		for (int j = 0; j <= i; ++j)
			s[j] = 1ll * s[j] * fac[j] % mod;
		while (cnt[i]--) F.push_back(s);
	} g = calc(0, F.size() - 1);
	int x = 1, res = 0;
	for (int i = 0; i < n; ++i) x = 1ll * ((W + n - i) % mod) * x % mod;
	for (int k = 0; k < g.size() && x; ++k) {
		res += 1ll * g[k] * (1ll * x * ifac[n + k] % mod) % mod;
		if (res >= mod) res -= mod;
		x = 1ll * ((W - k) % mod) * x % mod;
	} printf("%d\n", res);
	return 0;
}
posted @   Smallbasic  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
点击右上角即可分享
微信分享提示