Solution -「Gym 102798E」So Many Possibilities...
\(\mathcal{Description}\)
Link.
给定非负整数序列 \(\{a_n\}\) 和 \(m\),每次随机在 \(\{a\}\) 中取一个非零的 \(a_i\)(保证存在),令其 \(-1\),重复 \(m\) 次,求最终 \(\{a\}\) 中 \(0\) 的期望个数。
\(n\le15\),\(m\le100\)。
\(\mathcal{Solution}\)
既然有 DP of DP,我觉得这种题就叫 DP and DP。(
看到 \(n\le15\),想要状压,但无论如何都不能完整记录 \(\{a\}\) 的状态,也就不可能及时知道某个 \(a\) 会否变成 \(0\),怎么办呢?
既然不知道,我们索性不去动它们——设前 \(i\) 次操作后,\(\{a\}\) 中为 \(0\) 的下标集合为 \(S\), 我们只落实对 \(S\) 中元素造成影响的操作,共 \(\sum_{i\in S}a_i\) 次;而对于剩下 \(\left(i-\sum_{i\in S}a_i\right)\) 次,只记录为“它们会影响某个不在 \(T\) 中元素”,其中 \(T\) 是进行这个操作时的 \(0\) 值集合;“某个”是具体的,但尚未确定的一个,所以提供概率 \(\frac{1}{n-|T|}\)。另一方面,只有在扩充 \(S\) 时来确定若干“某个”,此时就只需要组合选取,而不需要乘概率了。那么摆出式子,令 \(f(i,S)\) 表示 \(i\) 次操作后,\(0\) 值集合为 \(S\) 的概率(概率计算方式如前文),则:
\]
思考此时得到的,应该用于计算答案的 \(f(m,S)\) 意味什么:落在 \(S\) 内的操作,它们是正常的,而其余的 \(\left(m-\sum_{i\in S}a_i\right)\) 次,它们一定落在 \(U\setminus S\)(\(U\) 为全集)中,遗漏的仅仅是方案数!所以在 \(f\) 的目标状态为基础,再来一个 DP:令 \(g(i,S)\) 表示有 \(i\) 次操作落在 \(S\),且 \(S\) 中不存在 \(0\) 值的方案数,简单地,任取一个 \(x\in S\),得到转移:
\]
最终答案则为:
\]
复杂度为 \(\mathcal O(m(n+m)2^n)\)。
\(\mathcal{Code}\)
/*~Rainybunny~*/
#include <cstdio>
#define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
#define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i )
inline int imin( const int a, const int b ) { return a < b ? a : b; }
typedef long double LD;
#define double LD
const int MAXN = 15, MAXM = 100;
int n, m, a[MAXN + 5], sum[1 << MAXN], bitc[1 << MAXN], bitw[1 << MAXN];
double comb[MAXM + 5][MAXM + 5], f[2][1 << MAXN], g[MAXM + 5][1 << MAXN];
inline void init() {
comb[0][0] = 1.;
rep ( i, 1, m ) {
comb[i][0] = 1.;
rep ( j, 1, i ) comb[i][j] = comb[i - 1][j] + comb[i - 1][j - 1];
}
}
inline void getF() {
f[0][0] = 1.;
rep ( i, 1, ( 1 << n ) - 1 ) bitc[i] = bitc[i ^ ( i & -i )] + 1;
for ( int i = 1, sta = 1; i <= m; ++i, sta ^= 1 ) {
rep ( S, 0, ( 1 << n ) - 1 ) {
f[sta][S] = 0.;
rep ( j, 0, n - 1 ) if ( S >> j & 1 ) {
f[sta][S] += i < sum[S ^ 1 << j] + 1 ? 0 :
comb[i - sum[S ^ 1 << j] - 1][a[j] - 1] * f[!sta][S ^ 1 <<j];
}
f[sta][S] /= n - bitc[S] + 1;
if ( n > bitc[S] ) f[sta][S] += f[!sta][S] / ( n - bitc[S] );
// fprintf( stderr, "f(%d,%d)=%f\n", i, S, f[sta][S] );
}
}
}
inline void getG() {
rep ( i, 2, ( 1 << n ) - 1 ) bitw[i] = bitw[i >> 1] + 1;
rep ( S, 0, ( 1 << n ) - 1 ) g[0][S] = 1.;
rep ( i, 1, m ) {
rep ( S, 1, ( 1 << n ) - 1 ) {
int v = bitw[S & -S]; double &cur = g[i][S];
rep ( j, 0, imin( i, a[v] - 1 ) ) {
cur += g[i - j][S ^ 1 << v] * comb[i][j];
}
// fprintf( stderr, "g(%d,%d)=%.0f\n", i, S, g[i][S] );
}
}
}
int main() {
scanf( "%d %d", &n, &m ), init();
rep ( i, 0, n - 1 ) scanf( "%d", &a[i] ), sum[1 << i] = a[i];
rep ( S, 1, ( 1 << n ) - 1 ) sum[S] = sum[S & -S] + sum[S ^ ( S & -S )];
getF(), getG();
double ans = 0.;
rep ( S, 0, ( 1 << n ) - 1 ) if ( m >= sum[S] ) {
ans += f[m & 1][S] * g[m - sum[S]][repS ^ S] * bitc[S];
}
printf( "%.12Lf\n", ans );
return 0;
}
Solution -「Gym 102798E」So Many Possibilities...的更多相关文章
- Solution -「Gym 102979E」Expected Distance
\(\mathcal{Description}\) Link. 用给定的 \(\{a_{n-1}\},\{c_n\}\) 生成一棵含有 \(n\) 个点的树,其中 \(u\) 连向 \([1, ...
- Solution -「Gym 102979L」 Lights On The Road
\(\mathcal{Description}\) Link. 给定序列 \(\{w_n\}\),选择 \(i\) 位置的代价为 \(w_i\),要求每个位置要不被选择,要不左右两个位置至少被 ...
- Solution -「Gym 102956F」Find the XOR
\(\mathcal{Description}\) Link. 给定 \(n\) 个点 \(m\) 条边的连通无向图 \(G\),边有边权.其中 \(u,v\) 的距离 \(d(u,v)\) ...
- Solution -「Gym 102956B」Beautiful Sequence Unraveling
\(\mathcal{Description}\) Link. 求长度为 \(n\),值域为 \([1,m]\) 的整数序列 \(\lang a_n\rang\) 的个数,满足 \(\not\ ...
- Solution -「Gym 102956F」Border Similarity Undertaking
\(\mathcal{Description}\) Link. 给定一张 \(n\times m\) 的表格,每个格子上写有一个小写字母.求其中长宽至少为 \(2\),且边界格子上字母相同的矩 ...
- Solution -「Gym 102956A」Belarusian State University
\(\mathcal{Description}\) Link. 给定两个不超过 \(2^n-1\) 次的多项式 \(A,B\),对于第 \(i\in[0,n)\) 个二进制位,定义任意一个二元 ...
- Solution -「Gym 102798I」Sean the Cuber
\(\mathcal{Description}\) Link. 给定两个可还原的二阶魔方,求从其中一个状态拧到另一个状态的最小步数. 数据组数 \(T\le2.5\times10^5\). ...
- Solution -「Gym 102798K」Tree Tweaking
\(\mathcal{Description}\) Link. 给定排列 \(\{p_n\}\),求任意重排 \(p_{l..r}\) 的元素后,将 \(\{p_n\}\) 依次插入二叉搜索树 ...
- Solution -「Gym 102759I」Query On A Tree 17
\(\mathcal{Description}\) Link. 给定一棵含 \(n\) 个结点的树,结点 \(1\) 为根,点 \(u\) 初始有点权 \(a_u=0\),维护 \(q\) 次 ...
随机推荐
- Linux上天之路(十六)之Shell编程一
用户在命令行输入命令后,一般情况下Shell会fork并exec该命令,但是Shell的内建命令例外,执行内建命令相当于调用Shell进程中的一个函数,并不创建新的进程.以前学过的cd.alias.u ...
- Linux内核模块学习
注:本文是<Linux设备驱动开发详解:基于最新的Linux 4.0内核 by 宋宝华 >一书学习的笔记,大部分内容为书籍中的内容. 书籍可直接在微信读书中查看:Linux设备驱动开发详解 ...
- 友善之臂mini2440光盘资料下载FriendlyARM-2440-DVD.7z
这是我目前找到最全面的友善之臂mini2440的光盘资料了,几乎支持mini2440的各种lcd屏幕.另外,Windows平台工具文件夹下还有版本比较新的MiniTools,这是一个非常好用的软件! ...
- Texture+PBR两种工作流程
一.导入Texture 1.Inpspector TextureSize 2的n次幂,底层图形学需要,计算更快:不使用2的倍数,系统也会添加像素补全2n: 有最大尺寸限制8k,cubemap最高4k: ...
- PkavHTTPFuzzer爆破带验证码的后台密码
之前对暴力破解这块并没有做系统的总结,况且登录这块也是个重头戏,所以我想总结总结. 环境准备 1.用phpstudy搭建phpwms1.1.2演示环境 2.pkavhttpfuzzer工具 漏洞复现 ...
- 我以订披萨为例,给女朋友详细讲了Java设计模式的3种工厂模式
摘要:工厂模式是将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦.从而提高项目的扩展和维护性. 本文分享自华为云社区<[Java设计模式]用 披萨订购案例 详 ...
- win+ r 命令
Win 键+R calc:计算器 notepad:记事本 mspaint:画图 cmd:控制台 control:控制面板 desk.cpl:打开控制面板中的桌面设置 main.cpl:鼠标设置 ine ...
- JSP页面打印输出,两种方法。out、《%=
使用out.println()输出: <%@ page contentType="text/html;charset=UTF-8"%> <html> < ...
- 申请Namecheap的.me 顶级域名以及申请ssl认证--github教育礼包之namecheap
关于教育礼包的取得见另一篇随笔,在那里笔者申请了digital ocean的vps(虚拟专用主机),跟阿里云差不多,不过个人感觉比阿里云便宜好用一点. 有了自己的主机ip,就想到申请域名,方便好记,也 ...
- promise的队列,宏任务,微任务,同步任务
// promise里面有一个特别的任务,就是微任务 // 同步任务>微任务>宏任务 setTimeout(() => { console.log("setTimeout& ...