Processing math: 100%

【CTS 2019】珍珠

Problem#

Description#

n 个在范围 [1,D] 内的整数均匀随机变量。

求至少能选出 m 个瓶子,使得存在一种方案,选择一些变量,并把选出来的每一个变量放到一个瓶子中,满足每个瓶子都恰好装两个值相同的变量的概率。

请输出概率乘上 Dn 后对 998244353 取模的值。取模部分说明可参考 。

Range#

0m109,1n109,1D105

Algorithm#

FFT ,生成函数

Mentality#

对于 2m>nn2mD 的情况先特判掉。

不难发现,设 ai 为颜色 i 出现的次数,我们要求的就是能满足 ai mod 2n2m 的方案数。

fi 为恰好有 i 种颜色出现次数为奇数的方案数,则有:

ans=n2mi=0fi

写出 fi 的表达式之后不太好求,我们需要令限制更少一点。

考虑钦定 i 个颜色的出现次数为奇数,设 hi 为,对于钦定的某 i 种颜色,使得出现次数为奇数,且其他颜色出现次数随意的方案数。

gi=(Di)hi ,也就是对于每种不同的钦定方案,我们将其求和。

那么根据定义,必然有等式:

gi=(ji)fj

因为每个 fj 都会被 gi 中的 (ji) 种钦定方案算到。

利用指数形生成函数 cnxii!=ecx 可得:

hi=n![xn](exex2)i(ex)Di=n!2i[xn]ij=0(ij)ejx(ex)ijeDi=n!2iij=0(ij)(1)ij[xn]eD+2j2i=n!2iij=0(iij)(1)j[xn]eD2j

随后因为 [xn]ecx=cnn! ,直接代入得:

hi=n!2iij=0(iij)(1)j(D2j)nn!=i!2iij=01(ij)!(1)j(D2j)nj!

这样就可以卷积了。

然后根据定义式直接算出 {gi}

根据二项式反演可得:

fi=Dj=i(1)ji(ji)gj=Dij=0(1)j(j+ii)gj+i=1i!Dij=0(1)jj!(j+i)!gj+i

pDji=gj+i(j+i)!,则有:

fi=1i!Dij=0(1)jj!pDji

这样就可以卷积了。

Code#

Copy
#include <cmath> #include <cstdio> #include <iostream> using namespace std; #define LL long long #define go(G, x, i, v) \ for (int i = G.hd[x], v = G.to[i]; i; v = G.to[i = G.nx[i]]) #define inline __inline__ __attribute__((always_inline)) inline LL read() { LL x = 0, w = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') w = -1; ch = getchar(); } while (isdigit(ch)) { x = (x << 3) + (x << 1) + ch - '0'; ch = getchar(); } return x * w; } const int Max_n = 8e5 + 5, mod = 998244353; int D, n, m; int fac[Max_n], ifac[Max_n]; int f[Max_n], g[Max_n], G[Max_n]; int ksm(int a, int b = mod - 2) { int res = 1; for (; b; b >>= 1, a = (LL)a * a % mod) if (b & 1) res = (LL)res * a % mod; return res; } namespace Poly { int len, bit, rev[Max_n]; void init(int n) { len = 1 << (bit = log2(n) + 1); for (int i = 0; i < len; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << bit - 1); } void dft(int *f, bool t) { for (int i = 0; i < len; i++) if (rev[i] > i) swap(f[i], f[rev[i]]); for (int l = 1; l < len; l <<= 1) { int Wn = ksm(3, (mod - 1) / (l << 1)); if (t) Wn = ksm(Wn); for (int i = 0; i < len; i += l << 1) { int Wnk = 1; for (int j = i; j < i + l; j++, Wnk = (LL)Wnk * Wn % mod) { int x = f[j], y = (LL)f[j + l] * Wnk % mod; f[j] = (x + y) % mod, f[j + l] = (x - y + mod) % mod; } } } if (t) for (int i = 0, Inv = ksm(len); i < len; i++) f[i] = (LL)f[i] * Inv % mod; } void Mul(int *f, int *g, int N) { init(N); dft(f, 0), dft(g, 0); for (int i = 0; i < len; i++) f[i] = (LL)f[i] * g[i] % mod; dft(f, 1), dft(g, 1); } } // namespace Poly using namespace Poly; namespace Input { void main() { D = read(), n = read(), m = read(); } } // namespace Input namespace Init { void main() { fac[0] = 1; for (int i = 1; i <= D; i++) fac[i] = (LL)fac[i - 1] * i % mod; ifac[D] = ksm(fac[D]); for (int i = D; i; i--) ifac[i - 1] = (LL)ifac[i] * i % mod; } } // namespace Init namespace Solve { int C(int n, int m) { if (n < m || m < 0) return 0; return (LL)fac[n] * ifac[m] % mod * ifac[n - m] % mod; } void main() { if (2 * m > n) { puts("0"); return; } if (D <= n - 2 * m) { printf("%d\n", ksm(D, n)); return; } for (int i = 0, t = 1; i <= D; i++, t *= -1) { G[i] = ifac[i]; g[i] = (LL)(t + mod) * ksm((D - 2 * i + mod) % mod, n) % mod * ifac[i] % mod; } Mul(G, g, D + 1 << 1); for (int i = 0; i <= D; i++) G[i] = (LL)ksm(ksm(2, i)) * G[i] % mod * fac[i] % mod * C(D, i) % mod; for (int i = 0, t = 1; i <= D; i++, t *= -1) { g[i] = (LL)G[D - i] * fac[D - i] % mod; f[i] = (LL)(t + mod) * ifac[i] % mod; } Mul(f, g, D + 1 << 1); int ans = 0; for (int i = 0; i <= n - 2 * m; i++) (ans += (LL)f[D - i] * ifac[i] % mod) %= mod; cout << ans << endl; } } // namespace Solve int main() { #ifndef ONLINE_JUDGE freopen("3120.in", "r", stdin); freopen("3120.out", "w", stdout); #endif Input::main(); Init::main(); Solve::main(); }
posted @   洛水·锦依卫  阅读(174)  评论(0编辑  收藏  举报
编辑推荐:
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· C# 深度学习:对抗生成网络(GAN)训练头像生成模型
阅读排行:
· 趁着过年的时候手搓了一个低代码框架
· 本地部署DeepSeek后,没有好看的交互界面怎么行!
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· 乌龟冬眠箱湿度监控系统和AI辅助建议功能的实现
历史上的今天:
2019-05-08 【SDOI 2015】约数个数和
点击右上角即可分享
微信分享提示

目录

目录

×