@description@

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

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

请输出概率乘上 \(D^n\) 后对 \(998244353\) 取模的值。

原题传送门。

@solution@

记 \(l = \min\{n - 2m, D\}\)。不难想到枚举出现次数为奇数的变量个数 \(i\),列式子:

\[n!\times[x^n]\sum_{i=0}^{l}{D\choose i}(\frac{e^x - e^{-x}}{2})^i(\frac{e^x + e^{-x}}{2})^{D-i}
\]

然后二项式展开 + 整理化简得到:

\[\frac{D!}{2^D}\times\sum_{i=0}^{D}\sum_{p=0}^{i}\sum_{q=0}^{D-i} \frac{(-1)^{i-p}(2p+2q-D)^n}{p!q!(i-p)!(D-i-q)!}
\]

然后我就到此为止了。不过这个思路是可以继续往下推导的,可以参考这篇博客。出题人也有一个关于这种推导方法的解释(还没仔细看,改天补坑.jpg)。

有一个较简单的推导方法。上式中出现了 3 个 \(\sum\),远远超过了一个中老年菜鸡选手的承受范围。

我们不妨设法去掉 1 个,然后再用常规卷积方法优化。

不妨钦定选 i 个奇数变量,其他的任意选,得到表达式:

\[\begin{aligned}
g_i &= n!\times{D \choose i}\times [x^n](\frac{e^x - e^{-x}}{2})^ie^{(D-i)x} \\
&= n!\times{D \choose i}\times [x^n]\sum_{j=0}^i{i\choose j}e^{(2j-2i+D)x}
\end{aligned}
\]

可以发现我们少了一次二项式展开。把 \({i\choose j}\) 拆开就可以直接卷积了。

设 \(f_i\) 表示恰好 i 个奇数变量的方案数,那么有 \(g_i = \sum_{j=i}^{D}{j\choose i}f_j\),二项式反演一下:

\[f_n = \sum_{i=n}^{D}(-1)^{i-n}{i\choose n}g_i
\]

这玩意也可以卷积。然后就做完了。

@accepted code@

#include <cstdio>
#include <algorithm>
using namespace std; const int MOD = 998244353;
const int MAXN = 400000; inline int add(int x, int y) {x += y; return x >= MOD ? x - MOD : x;}
inline int sub(int x, int y) {x -= y; return x < 0 ? x + MOD : x;}
inline int mul(int x, int y) {return 1LL * x * y % MOD;} int pow_mod(int b, int p) {
int ret = 1;
for(int i=p;i;i>>=1,b=mul(b,b))
if( i & 1 ) ret = mul(ret, b);
return ret;
} int w[20], iw[20], fct[MAXN + 5], ifct[MAXN + 5], inv[MAXN + 5];
void init() {
for(int i=0;i<20;i++) {
w[i] = pow_mod(3, (MOD - 1) / (1 << i));
iw[i] = pow_mod(w[i], MOD - 2);
}
fct[0] = 1; for(int i=1;i<=MAXN;i++) fct[i] = mul(fct[i - 1], i);
ifct[MAXN] = pow_mod(fct[MAXN], MOD - 2);
for(int i=MAXN-1;i>=0;i--) ifct[i] = mul(ifct[i + 1], i + 1);
for(int i=1;i<=MAXN;i++) inv[i] = mul(fct[i - 1], ifct[i]);
}
void ntt(int *A, int n, int type) {
for(int i=0,j=0;i<n;i++) {
if( i < j ) swap(A[i], A[j]);
for(int l=(n>>1);(j^=l)<l;l>>=1);
}
for(int i=1,s=2,t=1;s<=n;i++,s<<=1,t<<=1) {
int u = (type == 1 ? w[i] : iw[i]);
for(int j=0;j<n;j+=s) {
for(int k=0,p=1;k<t;k++,p=mul(p,u)) {
int x = A[j + k], y = mul(p, A[j + k + t]);
A[j + k] = add(x, y), A[j + k + t] = sub(x, y);
}
}
}
if( type == -1 ) {
for(int i=0;i<n;i++)
A[i] = mul(A[i], inv[n]);
}
}
int length(int n) {
int len; for(len = 1; len <= n; len <<= 1);
return len;
}
int comb(int n, int m) {
return mul(fct[n], mul(ifct[m], ifct[n - m]));
}
int D, n, m;
int f[MAXN + 5], g[MAXN + 5], a[MAXN + 5], b[MAXN + 5];
void get() {
for(int i=0;i<=D;i++) a[i] = mul((i & 1 ? MOD - 1 : 1), mul(pow_mod(sub(D, 2*i), n), ifct[i]));
for(int i=0;i<=D;i++) b[i] = ifct[i];
int len = length(2*D); ntt(a, len, 1), ntt(b, len, 1);
for(int i=0;i<len;i++) g[i] = mul(a[i], b[i]);
ntt(g, len, -1);
for(int i=1;i<=D;i++) g[i] = mul(g[i], mul(comb(D, i), mul(fct[i], pow_mod(2, MOD - 1 - i))));
for(int i=D+1;i<len;i++) g[i] = 0; for(int i=0;i<len;i++) a[i] = b[i] = 0;
for(int i=0;i<=D;i++) a[D - i] = mul(g[i], fct[i]);
for(int i=0;i<=D;i++) b[i] = (i & 1 ? sub(0, ifct[i]) : ifct[i]);
ntt(a, len, 1), ntt(b, len, 1);
for(int i=0;i<len;i++) f[i] = mul(a[i], b[i]);
ntt(f, len, -1), reverse(f, f + D + 1);
for(int i=0;i<=D;i++) f[i] = mul(f[i], ifct[i]);
} int main() {
init(), scanf("%d%d%d", &D, &n, &m), get();
int l = min(D, n - 2*m), ans = 0;
for(int i=0;i<=l;i++) ans = add(ans, f[i]);
printf("%d\n", ans);
}

@details@

感觉第二种做法比第一种做法更自然一些?(虽然我觉得一般都会先想到第一种做法)

看了一下某谷的题解,发现好像还有线性做法?

我感觉我的组合数学现在可能只会卷积模板题了。

@loj - 3120@ 「CTS2019 | CTSC2019」珍珠的更多相关文章

  1. 【LOJ】#3120. 「CTS2019 | CTSC2019」珍珠

    LOJ3120 52pts \(N - D >= 2M\)或者\(M = 0\)那么就是\(D^{N}\) 只和数字的奇偶性有关,如果有k个奇数,那么必须满足\(N - k >= 2M\) ...

  2. Loj #3124. 「CTS2019 | CTSC2019」氪金手游

    Loj #3124. 「CTS2019 | CTSC2019」氪金手游 题目描述 小刘同学是一个喜欢氪金手游的男孩子. 他最近迷上了一个新游戏,游戏的内容就是不断地抽卡.现在已知: - 卡池里总共有 ...

  3. LOJ 3120: 洛谷 P5401: 「CTS2019 | CTSC2019」珍珠

    题目传送门:LOJ #3120. 题意简述: 称一个长度为 \(n\),元素取值为 \([1,D]\) 的整数序列是合法的,当且仅当其中能够选出至少 \(m\) 对相同元素(不能重复选出元素). 问合 ...

  4. LOJ 3124 「CTS2019 | CTSC2019」氪金手游——概率+树形DP

    题目:https://loj.ac/problem/3124 看了题解:https://www.cnblogs.com/Itst/p/10883880.html 先考虑外向树. 考虑分母是 \( \s ...

  5. loj3120 「CTS2019 | CTSC2019」珍珠

    link .... 感觉自己太颓废了....还是来更题解吧...[话说写博客会不会涨 rp 啊 qaq ? 题意: 有 n 个物品,每个都有一个 [1,D] 中随机的颜色,相同颜色的两个物品可以配对. ...

  6. LOJ #3119「CTS2019 | CTSC2019」随机立方体 (容斥)

    博客链接 里面有个下降幂应该是上升幂 还有个bk的式子省略了k^3 CODE 蛮短的 #include <bits/stdc++.h> using namespace std; const ...

  7. LOJ #3119. 「CTS2019 | CTSC2019」随机立方体 组合计数+二项式反演

    好神的一道计数题呀. code: #include <cstdio> #include <algorithm> #include <cstring> #define ...

  8. 「CTS2019 | CTSC2019」氪金手游 解题报告

    「CTS2019 | CTSC2019」氪金手游 降 智 好 题 ... 考场上签到失败了,没想容斥就只打了20分暴力... 考虑一个事情,你抽中一个度为0的点,相当于把这个点删掉了(当然你也只能抽中 ...

  9. 「CTS2019 | CTSC2019」随机立方体 解题报告

    「CTS2019 | CTSC2019」随机立方体 据说这是签到题,但是我计数学的实在有点差,这里认真说一说. 我们先考虑一些事实 如果我们在位置\((x_0,y_0,z_0)\)钦定了一个极大数\( ...

随机推荐

  1. orcle报错:ORA-12737:Instant Client Light:unsupported server character set ZHS16GBK

    我们用Navacat连接Oracle数据库的时候,会提示ORA-12737:Instant Client Light:unsupported server character set ZHS16GBK ...

  2. Shift - And字符串快速处理 hdu5972+cf

    基础知识介绍 KMP就是不断往前找1的位置,而ShiftAnd经过三步处理已经完成这个迭代的过程了 如果匹配两个字符集有限的字符串的话,那么Shift-And比kmp要快,找区间内某字符串出现的数目也 ...

  3. 多线程(thread+queue 售票)

    一.理解 如果线程里每从队列里取一次,但没有执行task_done(),则join无法判断队列到底有没有结束,在最后执行个join()是等不到结果的,会一直挂起.可以理解为,每task_done一次 ...

  4. JUC(4)---java线程池原理及源码分析

    线程池,既然是个池子里面肯定就装很多线程. 如果并发的请求数量非常多,但每个线程执行的时间很短,这样就会频繁的创建和销毁 线程,如此一来会大大降低系统的效率.可能出现服务器在为每个请求创建新线程和销毁 ...

  5. APM 上报信息分析与应用

    在入正题之前我们再回顾下它的架构图: 本文章主要分析AMP各索引的作用,与及结合1.7环境上已接入的服务数据对比后,对索引中的主要字段进行解析.文章分为四个小章节. 1.索引类型 apm索引分为四种类 ...

  6. PSR-0到PSR-4编程规范

    PHP-FIG 在说啥是PSR-[0-4]规范的之前,我觉得我们有必要说下它的发明者和规范者:PHP-FIG,它的网站是:www.php-fig.org.就是这个联盟组织发明和创造了PSR-[0-4] ...

  7. JAVA定义变量和基础的数据类型和关键字

      标识符语法 1)java中定义标识符格式以字母,数字,下划线,$符合组成,不能以数字开头,且不能为  java中的关键字.         2)标识符意义要明确,不要乱起         3)标识 ...

  8. eatwhatApp开发实战(十三)

    这次内容,我们就项目中添加商店名称的EditText进行修改,让添加按钮随着edittext的内容而改变. 上代码,首先是xml文件上对两个控件的修改: <RelativeLayout andr ...

  9. [Objective-C] 005_Category(类别)

    Category的实际作用就是为已有的类来添加方法.为现有的类添加的方法可以先不用实现,在需要的时候再实现也是可以的.在我们的实际代码中如何来实现Category的呢?我们上篇的Person 类为例. ...

  10. Spring_Bean的配置方式

    1.通过工厂方法配置bean beans-factory.xml <?xml version="1.0" encoding="UTF-8"?> &l ...