[2018国家集训队][UOJ449] 喂鸽子 [dp+组合数学]
题面
思路
首先,这道题是可以暴力min-max反演+NTT做出来的......但是这个不美观,我来讲一个做起来舒服一点的做法
一个非常basic的idea:我们发现在一只鸽子吃饱以后再喂给它的玉米都是“无效”的,并且我们如此认为,那么有效的玉米数量是确定的:$nk$
吃饱序列和投喂序列
那么,我们考虑一个序列$r_i$,表示第$i$次喂完玉米之前,有多少只鸽子是吃饱的,我们称之为吃饱序列
注意到本题中每只鸽子互不相同,因此我们再确定一个“有效喂鸽子操作”的序列,我们称之为投喂序列
特别注意:吃饱序列的构造虽然部分依赖于投喂序列,但是投喂序列的出现概率是完全依赖于吃饱序列的
显然,对于一组操作序列和吃饱序列,我们可以得到这组序列出现的总概率:$Prob=\prod_{i=1}^{nk}P_{r_i}$
其中$P_i$表示吃饱了$i$个的情况下,下一个投喂选到我们的目标鸽子的概率
那么我们现在实际上把投喂序列变成了可以由吃饱序列求出来,而吃饱序列的下一项又反过来由投喂序列确定,这么一个情况
我们如果要考虑总贡献,我们发现还需要考虑最终成功完成一次有效投喂(注意因为前面算的是概率,这里只要随便投喂一个没吃饱的鸽子就可以了)的期望时间
这个时间$T_i=E_{r_i}$,其中$E_i=\frac{n}{n-i}$,这里表示在$i$个鸽子吃饱的前提下的有效投喂期望时间
那么,我们可以得到我们在确定了一个吃饱序列和对应的投喂序列时最终答案的表达式:$Ans=\prod_{i=1}{nk}P_{r_i}\sum_{i=1}{nk} E_{r_i}$
上式的两个部分分别代表每一个投喂序列出现的概率,以及这个吃饱序列的期望完成时间
转化为DP
这个东西不好处理,因为我们没有办法直接知道每次成功投喂以后会不会使吃饱序列的下一项+1(也就是有一只鸽子吃饱了)
注意到贡献都只和$r_i$有关系,而和目前没吃饱的鸽子吃掉的玉米的分配没有关系!
所以我们大可以随意分配这些没吃饱的鸽子吃掉的玉米,下文中简称为白玉米
那么我们可以基于上面的表达式得到一个$dp$的做法:
设$f[i][j]$表示投喂了$i$次,有$j$个鸽子吃饱了的总贡献,$g[i][j]$则表示上述情况出现的概率(也就是只考虑表达式中含$P_{r_i}$的部分)
那么我们把表达式转化一下:
$f[i][j]=\sum_{\lbrace r\rbrace} \prod_{x=1}{i}P_{r_x}\sum_{y=1}{i} E_{r_y}$
$f[i][j]=\sum_{\lbrace r\rbrace} (P_j\prod_{x=1}{i-1}P_{r_x})(E_j+\sum_{y=1}{i-1} E_{r_y})$
$f[i][j]=P_j\ast(\sum_{\lbrace r\rbrace} \prod_{x=1}{i-1}P_{r_x}\sum_{y=1}{i-1} E_{r_y})+P_j\ast E_j\ast(\sum_{\lbrace r\rbrace} \prod_{x=1}^{i-1}P_{r_x})$
$f[i][j]=P_jf[i-1][j]+P_jE_jg[i-1][j]$
这样我们就完成了没有新鸽子吃饱的情况下的$f[i][j]$的转移
那么对于$g[i][j]$的转移,很显然是$g[i][j]=P_jg[i-1][j]$,不再赘述
对于新加入的玉米使得一只鸽子吃饱的情况,我们需要对目前存在的白玉米进行染色,此时染色的方案数显然为$\binom{i-jk}{k-1}$
所以对于从$f[i][j]$到$f[i+1][j+1]$的转移,只需要在上面的转移的基础上乘上上述组合系数即可
若仍有疑问,可以参见代码的实现
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cassert>
#define MOD 998244353
#define ll long long
using namespace std;
inline int read(){
int re=0,flag=1;char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') flag=-1;
ch=getchar();
}
while(isdigit(ch)) re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
return re*flag;
}
inline int add(int a,int b){
a+=b;
if(a>=MOD) a-=MOD;
return a;
}
inline void addd(int &a,int b){
a+=b;
if(a>=MOD) a-=MOD;
}
inline int qpow(int a,int b){
int re=1;
while(b){
if(b&1) re=1ll*re*a%MOD;
a=1ll*a*a%MOD;b>>=1;
}
return re;
}
int n,m,fac[1000010],finv[1000010],inv[1000010];
inline void init(){
int i,len=1000000;
fac[0]=fac[1]=finv[0]=finv[1]=inv[1]=1;
for(i=2;i<=len;i++) inv[i]=1ll*(MOD-MOD/i)*inv[MOD%i]%MOD;
for(i=2;i<=len;i++) fac[i]=1ll*fac[i-1]*i%MOD;
finv[len]=qpow(fac[len],MOD-2);
for(i=len;i>2;i--) finv[i-1]=1ll*finv[i]*i%MOD;
}
inline int C(int x,int y){
if(x<0||y<0||x<y) return 0;
return 1ll*fac[x]*finv[y]%MOD*finv[x-y]%MOD;
}
int f[100010][110],g[100010][110],p[100010],e[100010];
int main(){
n=read();m=read();int i,j,tf,tg,tt;
init();
for(i=0;i<=n;i++) p[i]=inv[n-i],e[i]=1ll*n*inv[n-i]%MOD;
f[0][0]=0;g[0][0]=1;
for(i=0;i<n*m;i++){
for(j=0;j*m<=i;j++){
tg=1ll*g[i][j]*p[j]%MOD;
tf=add(1ll*f[i][j]*p[j]%MOD,1ll*p[j]*e[j]%MOD*g[i][j]%MOD);
tt=C(i-j*m,m-1);
addd(f[i+1][j],tf);
addd(g[i+1][j],tg);
addd(f[i+1][j+1],1ll*tf*tt%MOD);
addd(g[i+1][j+1],1ll*tg*tt%MOD);
}
}
// for(i=0;i<=n*m;i++) for(j=0;j*m<=i;j++) cout<<i<<' '<<j<<' '<<f[i][j]<<' '<<g[i][j]<<'\n';
cout<<(1ll*fac[n]*f[n*m][n]%MOD)<<'\n';
}
[2018国家集训队][UOJ449] 喂鸽子 [dp+组合数学]的更多相关文章
- P2183 [国家集训队]【一本通提高组合数学】礼物
[国家集训队]礼物 题目背景 一年一度的圣诞节快要来到了.每年的圣诞节小 E 都会收到许多礼物,当然他也会送出许多礼物.不同的人物在小 E 心目中的重要性不同,在小 E 心中分量越重的人,收到的礼物会 ...
- NOI 国家集训队论文集
鉴于大家都在找这些神牛的论文.我就转载了这篇论文合集 国家集训队论文分类 组合数学 计数与统计 2001 - 符文杰:<Pólya原理及其应用> 2003 - 许智磊:<浅谈补集转化 ...
- ACM/IOI 历年国家集训队论文集和论文算法分类整理
国家集训队1999论文集 陈宏:<数据结构的选择与算法效率--从IOI98试题PICTURE谈起> 来煜坤:<把握本质,灵活运用--动态规划的深入探讨> 齐鑫:<搜索方法 ...
- < < < 2013年国家集训队作业 > > >
完成题数/总题数: 道/37道 1. A1504. Book(王迪): 数论+贪心 ★★☆ 2013中国国家集训队第二次作业 2. A1505. 树(张闻涛): 倍增LCA+可 ...
- 洛谷 P1407 [国家集训队]稳定婚姻 解题报告
P1407 [国家集训队]稳定婚姻 题目描述 我国的离婚率连续7年上升,今年的头两季,平均每天有近5000对夫妇离婚,大城市的离婚率上升最快,有研究婚姻问题的专家认为,是与简化离婚手续有关. 25岁的 ...
- 洛谷 P1852 [国家集训队]跳跳棋 解题报告
P1852 [国家集训队]跳跳棋 题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在\(a\),\(b\), ...
- 洛谷 P1501 [国家集训队]Tree II 解题报告
P1501 [国家集训队]Tree II 题目描述 一棵\(n\)个点的树,每个点的初始权值为\(1\).对于这棵树有\(q\)个操作,每个操作为以下四种操作之一: + u v c:将\(u\)到\( ...
- 洛谷 P2757 [国家集训队]等差子序列 解题报告
P2757 [国家集训队]等差子序列 题目描述 给一个\(1\)到\(N\)的排列\(\{A_i\}\),询问是否存在 \[1 \le p_1<p_2<p_3<p_4<p_5& ...
- 洛谷 P1505 [国家集训队]旅游 解题报告
P1505 [国家集训队]旅游 题目描述 \(\tt{Ray}\) 乐忠于旅游,这次他来到了\(T\)城.\(T\)城是一个水上城市,一共有 \(N\) 个景点,有些景点之间会用一座桥连接.为了方便游 ...
随机推荐
- dubbo之监控中心(monitor)
一.monitor是dubbo框架中的一个监控中心.这个只是针对于消费者和提供者进行一个数据记录,不参与业务和使用.当然当monitor挂掉之后,也不会影响服务的正常运行. 二.在阿里的dubbo中也 ...
- DE1-SOC工程helloworld-第一篇(未完成)
1. 参考官方的文档,第一个问题就是电脑上需要安装ubuntu虚拟机吗? 2. 创建一个“Hello world”工程:在Linux terminal 上打印信息. 3. 说是让安装个EDS软件,先去 ...
- MyBatis-自定义结果映射规则
1.自定义结果集映射规则 ①查询 <!-- public Employee getEmpById(Integer id); --> <select id="getEmpBy ...
- Http接口系列:如何提高Http接口用例的数据稳定性
此文已由作者王婷英授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 为了尽可能多的释放手工测试,提高测试效率,我们都会想到使用自动化测试,如http接口自动化测试.doubbo ...
- JS dataTables
原文地址: http://www.cnblogs.com/haogj/archive/2011/03/04/1971328.html 数据来源有四种: 1. 网页DOM对象 $(document) ...
- Java开发工程师(Web方向) - 01.Java Web开发入门 - 第6章.蜂巢
第6章--蜂巢 蜂巢简介 网站开发完,就需要测试.部署.在服务器上运行. 网易蜂巢: 采用Docker容器化技术的云计算平台 https://c.163.com 容器管理:容器可被视作为云主机的服务器 ...
- 博客美化—添加萌萌的live2D看板娘(不能再简单了)
看着很多博客都有live2D的萌萌哒看板娘,我闲着有空说干就干. 从参考博客的附件中下载资源文件 waifu.css waifu-tips.js live2d.js flat-ui.min.css// ...
- yii的学习笔记 基本结构 自用
Yii 学习笔记 W:YII是什么? Q:Yii 是一个基于组件的高性能 PHP 框架,用于快速开发大型 Web 应用.它使Web开发中的 可复用度最大化,可以显著提高你的Web应用开发速度.Yii ...
- JAVA基础学习之路(七)对象数组的定义及使用
两种定义方式: 1.动态初始化: 定义并开辟数组:类名称 对象数组名[] = new 类名称[长度] 分布按成:类名称 对象数组名[] = null: 对象数组名 = new 类名称[长度]: 2 ...
- 基础的表ADT -数据结构(C语言实现)
读数据结构与算法分析 表的概述 形如A1,A2,A3... 操作合集 PrintList MakeEmpty Find Insert Delete 表的简单数组实现 分析: PrintList和Fin ...