@description@

老头子是小学校长,小学生(大哥)们都很听老头子的话。一天,老头子给小学生(大哥)们发苹果吃。

一共有 n 个小学生(大哥),老头子每一次会等概率选择一位小学生(大哥)并给他一个苹果。一个小学生(大哥)变得开心当且仅当他拥有的苹果数 ≥k。

因为老头子年纪大了,所以他想要你告诉他,期望多少次之后所有的小学生(大哥)都变得开心。

假设答案的最简分数形式为 a/b,你需要求出 w,满足 a≡b⋅w mod 998244353,且 0≤w<998244353。

Input format

一行两个数 n,k。

Output format

一行一个数表示答案。

Sample input

1 1

Sample output

1

Constraints

对于所有的数据,n≤50,k≤1000。

@solution@

uoj#449. 【集训队作业2018】喂鸽子

你可以通过搜索上面那道题的题解完成此题。

嗯好我们进入正题。首先一眼 min-max 容斥。问题转化 n 个人中选,前 m 个人第一个拥有苹果数 ≥ k 的期望次数。

假如我们知道在 m 个人中选,第一个拥有苹果数 ≥ k 的期望次数为 f[m]。则 n 个人中选,前 m 个人第一个拥有苹果数 ≥ k 的期望次数为 f[m]*n/m。

为什么?因为期望等于概率的倒数!有恰当的正确性证明,只是我概率论学得不好。

考虑怎么求解 f[m] 。我们假设如果出现拥有苹果数 ≥ k 的事件后,强制结束操作。

设在发第 i 个苹果之前,操作还未结束的概率为 p[m][i];设发了 i 个苹果,还是没有结束的方案数(即没有一个人的苹果数 ≥ k)为 g[m][i];设发了 i 个苹果,刚好结束(即第 i 个苹果发给了之前某个拥有 k-1 个苹果的人,使那个人拥有了 k 个苹果)的方案数为 h[m][i]。显然以上定义中第二维的大小 <= m*k。

于是可以得到如下几个关系式:

\[p[m][i] = p[m][i-1]*\frac{g[m][i-1]}{g[m][i-1]+h[m][i-1]}
\]

\[h[m][i] = m*C_{i-1}^{k-1}*g[m-1][i-k]
\]

\[g[m][i] = \sum_{j=0}^{k-1}g[m-1][i-j]*C_{i}^{j}
\]

\[f[m] = \sum_{i=0}^{m*k}\frac{h[m][i]}{g[m][i]+h[m][i]}*i
\]

注意到 g 的转移式中,可以通过将组合数拆成阶乘形式来进行卷积。

于是时间复杂度为 O(n^2klog(nk))。

最终答案 ans 的表达式为:

\[ans = \sum_{i=1}^{n}f[i]*\frac{n}{i}*C_n^i*(-1)^{i-1}
\]

代码实现的部分细节可能与上面描述的不一样(比如我的 p[m][i] 与 h[m][i] 是边算边求的),自行理解一下吧(因为我懒得改代码了)。

@accepted code@

#include<cstdio>
#include<algorithm>
using namespace std;
const int G = 3;
const int MAXN = 50;
const int MAXK = 1000;
const int MOD = 998244353;
int pow_mod(int b, int p) {
int ret = 1;
while( p ) {
if( p & 1 ) ret = 1LL*ret*b%MOD;
b = 1LL*b*b%MOD;
p >>= 1;
}
return ret;
}
int pw[20 + 5], ipw[20 + 5];
int fct[MAXN*MAXK + 5], inv[MAXN*MAXK + 5];
void init() {
fct[0] = 1;
for(int i=1;i<=MAXN*MAXK;i++)
fct[i] = 1LL*fct[i-1]*i%MOD;
inv[MAXN*MAXK] = pow_mod(fct[MAXN*MAXK], MOD-2);
for(int i=MAXN*MAXK-1;i>=0;i--)
inv[i] = 1LL*inv[i+1]*(i + 1)%MOD;
for(int i=1;i<=20;i++)
pw[i] = pow_mod(G, (MOD-1)/(1<<i)), ipw[i] = pow_mod(G, (MOD-1) - (MOD-1)/(1<<i));
}
int comb(int n, int m) {
return 1LL*fct[n]*inv[m]%MOD*inv[n-m]%MOD;
}
void ntt(int *A, int len, int type) {
for(int i=0,j=0;i<len;i++) {
if( i < j ) swap(A[i], A[j]);
for(int l=(len>>1);(j^=l)<l;l>>=1);
}
for(int i=1;(1<<i)<=len;i++) {
int s = (1<<i), t = (s>>1);
int u = (type == 1) ? pw[i] : ipw[i];
for(int j=0;j<len;j+=s) {
for(int k=0,p=1;k<t;k++,p=1LL*p*u%MOD) {
int x = A[j+k], y = 1LL*A[j+k+t]*p%MOD;
A[j+k] = (x + y)%MOD, A[j+k+t] = (x + MOD - y)%MOD;
}
}
}
if( type == -1 ) {
int inv = pow_mod(len, MOD-2);
for(int i=0;i<len;i++)
A[i] = 1LL*A[i]*inv%MOD;
}
}
int dp[MAXN + 5][MAXN*MAXK + 5], A[2*MAXN*MAXK + 5], B[2*MAXN*MAXK + 5], C[2*MAXN*MAXK + 5];
int main() {
init();
int n, k, ans = 0;
scanf("%d%d", &n, &k);
dp[0][0] = 1;
for(int i=1;i<=n;i++) {
int len; for(len = 1; len <= i*(k-1); len <<= 1);
for(int j=0;j<len;j++)
A[j] = B[j] = 0;
for(int j=0;j<k;j++)
B[j] = inv[j];
for(int j=0;j<=(i-1)*(k-1);j++)
A[j] = 1LL*dp[i-1][j]*inv[j]%MOD;
ntt(A, len, 1), ntt(B, len, 1);
for(int j=0;j<len;j++)
C[j] = 1LL*A[j]*B[j]%MOD;
ntt(C, len, -1);
for(int j=0;j<=i*(k-1);j++)
dp[i][j] = 1LL*C[j]*fct[j]%MOD;
}
for(int i=1;i<=n;i++) {
int g = 0, p = 1;
for(int j=0;j<=(i-1)*(k-1);j++) {
int a = 1LL*i*dp[i-1][j]%MOD*comb(j+k-1, k-1)%MOD;
int b = dp[i][j+k];
int c = pow_mod(a+b, MOD-2);
g = (g + 1LL*p*a%MOD*c%MOD*(j+k)%MOD)%MOD;
p = 1LL*p*b%MOD*c%MOD;
}
int f = 1LL*pow_mod(i, MOD-2)*n%MOD*comb(n, i)%MOD*pow_mod(MOD-1, i-1)%MOD;
ans = (ans + 1LL*f*g%MOD)%MOD;
}
printf("%d\n", ans);
}

@details@

这个题与 uoj#449. 【集训队作业2018】喂鸽子 可能的确是同一道题(连用暴力模拟求期望帮助验证正确性都是一样的)。

只是我不知道哪一道题先出现,所以也不好判断这个是否可以定义为原题。

好像是在雅礼集训的时候讲课讲过这个题,还讲过不用 min-max 容斥的做法。但是好像找不着当初那个课件。。。

考试后,我对比了一下我考场上想的做法和标算的做法,发现好像不太一样。。。

可以去搜 uoj 的那道题的题解了解一下正确的切题姿势。

注意刚好结束时,最后一颗苹果一定发给那个 k 个苹果的人。

就是因为这个细节一开始写挂了。。。

@noi.ac - 443@ 老头子的话的更多相关文章

  1. # NOI.AC省选赛 第五场T1 子集,与&最大值

    NOI.AC省选赛 第五场T1 A. Mas的童年 题目链接 http://noi.ac/problem/309 思路 0x00 \(n^2\)的暴力挺简单的. ans=max(ans,xor[j-1 ...

  2. NOI.ac #31 MST DP、哈希

    题目传送门:http://noi.ac/problem/31 一道思路好题考虑模拟$Kruskal$的加边方式,然后能够发现非最小生成树边只能在一个已经由边权更小的边连成的连通块中,而树边一定会让两个 ...

  3. NOI.AC NOIP模拟赛 第五场 游记

    NOI.AC NOIP模拟赛 第五场 游记 count 题目大意: 长度为\(n+1(n\le10^5)\)的序列\(A\),其中的每个数都是不大于\(n\)的正整数,且\(n\)以内每个正整数至少出 ...

  4. NOI.AC NOIP模拟赛 第六场 游记

    NOI.AC NOIP模拟赛 第六场 游记 queen 题目大意: 在一个\(n\times n(n\le10^5)\)的棋盘上,放有\(m(m\le10^5)\)个皇后,其中每一个皇后都可以向上.下 ...

  5. NOI.AC NOIP模拟赛 第二场 补记

    NOI.AC NOIP模拟赛 第二场 补记 palindrome 题目大意: 同[CEOI2017]Palindromic Partitions string 同[TC11326]Impossible ...

  6. NOI.AC NOIP模拟赛 第一场 补记

    NOI.AC NOIP模拟赛 第一场 补记 candy 题目大意: 有两个超市,每个超市有\(n(n\le10^5)\)个糖,每个糖\(W\)元.每颗糖有一个愉悦度,其中,第一家商店中的第\(i\)颗 ...

  7. NOI.AC NOIP模拟赛 第四场 补记

    NOI.AC NOIP模拟赛 第四场 补记 子图 题目大意: 一张\(n(n\le5\times10^5)\)个点,\(m(m\le5\times10^5)\)条边的无向图.删去第\(i\)条边需要\ ...

  8. NOI.AC NOIP模拟赛 第三场 补记

    NOI.AC NOIP模拟赛 第三场 补记 列队 题目大意: 给定一个\(n\times m(n,m\le1000)\)的矩阵,每个格子上有一个数\(w_{i,j}\).保证\(w_{i,j}\)互不 ...

  9. NOI.AC WC模拟赛

    4C(容斥) http://noi.ac/contest/56/problem/25 同时交换一行或一列对答案显然没有影响,于是将行列均从大到小排序,每次处理限制相同的一段行列(呈一个L形). 问题变 ...

随机推荐

  1. win10 下安装 neo4j

    1.neo4j介绍 neo4j是基于Java语言编写图形数据库.图是一组节点和连接这些节点的关系.图形数据库也被称为图形数据库管理系统或GDBMS.详细介绍可看Neo4j 教程 2.安装Java jd ...

  2. appium+python 启动一个app步骤

    询问度娘搭好appium和python环境,开启移动app自动化的探索(基于Android),首先来记录下如何启动待测的app吧! 如何启动APP?1.获取包名:2.获取launcherActivit ...

  3. java-异常处理2

    一 编译时异常和运行时异常的区别 java认为如果你的程序有问题,你应该让调用者知道. 例如:面包,长毛了.用户去买了,用户可能会挂 .应该在面包上贴上标签(异常). java 如果在函数内抛出Exc ...

  4. DNS客户端配置文件/etc/resolv.conf

    本来不应该把DNS客户端配置文件放在这里来说,但由于新手弟兄上网时,虽然能拔号,但不能以域名访问.究其原因是由于没有修改 /etc/resolv.conf 文件: /etc/resolv.conf 里 ...

  5. 【Codeforces Round #430 (Div. 2) B】Gleb And Pizza

    [链接]点击打开链接 [题意] 在这里写题意 [题解] 根据圆心到原点的距离这个东西判断一下圆在不在那个环里面就好 [错的次数] 0 [反思] 在这了写反思 [代码] #include <cst ...

  6. java中的线程(2):如何正确停止线程之2种常见停止方式

    1.常见停止方式 结束run函数,run中含退出标志位. 使用interrupt()方法中断线程 使用stop方法暴力终止(已经弃用) 2.结束run class TestThread extends ...

  7. json原生解析

    身为新手,在运用网络解析json数据的时候,发现先会用Gson等框架解析json,然后就懒起来学原生解析了,这下在看别人写的demo的时候就尴尬了,一块块的,不懂写什么,气氛十分尴尬. 不多说,先来条 ...

  8. js的各种获取大小

    相信大家也经常会被js的获取大小搞得头昏脑胀,到底应该用哪种方式获取才是我要的那种大小呢 好啦,在此我帮大家整理好我知道的那些. window.screen.availHeight  获取的是当前电脑 ...

  9. 如何把pdf文档转化为word

    在工作中常常遇到大量的pdf文档,再加工进行处理文件,特别的不方便,需要转换为WORD. 尝试如下: 使用wps自带的工具转换,提示需要是会员才能进行.否则只能进行5页以下的转换. 再想是不是又有个这 ...

  10. Serializable 可串行化接口

    Serializable 可串行化接口 定义一个User类,实现Serializable接口: package com.monkey1025; import java.io.Serializable; ...