题解: CF768D Jon and Orbs

发布时间 2023-10-10 22:12:28作者: superl61

题解: CF768D Jon and Orbs

一句话体面:有k种不同的物品,每天等概率任取一种(不一定是新的种类)。q组询问,每组给出一个p,问取完这k件物品的概率不小于\(\frac{p}{2000}\)的最小天数

不用说,肯定是概率DP了

1.定义 :\(f_{i,j}\) 表示前\(i\)天选取了 \(j\) 种物品的概率(\(P.S.\)该定义不是最终的准确定义!请耐心往下读!)

则分两类情况转换:

(1)前\(i-1\)天已经选了\(j\)种物品了,第\(i\)天选了一个旧的,则有

\[f_{i,j}+=f_{i-1,j}*\frac{j}{k} \]

(2)前\(i-1\)天选了\(j-1\)种物品,第\(i\)天选了一个新的,则有

\[f_{i,j}+=f_{i-1,j-1}*\frac{k-(j-1)}{k} \]

整合一下两种情况,则有

\[f_{i,j}=f_{i-1,j}*\frac{j}{k}+f_{i-1,j-1}*\frac{k-(j-1)}{k} \]

2.初始值:(\(P.S.\)因为初始值的问题我调了2个多小时!!!大家一定要想清楚再下笔!)

一开始我是这么写的:

F(i,1,M) f[i][1]=1;

一看别人的题解发现是这样的:

f[0][0]=1;

当场感觉不妙,再仔细想了想有道理:前\(0\)天选\(0\)种的概率肯定就是\(1\)啊,那前\(i\)天不是至少会选到一种吗,概率为什么不是1???

回到定义去找问题:发现“选了\(j\)种物品”其实不够准确,前\(i\)天选了1种物品,是每一天只需要随便选一种就行了吗?

再三思索后终于发现并不是这样的!物品种类不能多也不能少,必须刚好是\(1\)种!!!,所以将定义说清楚了应该是: \(i\)天只选了 \(j\) 种物品的概率

所以得到如下边界:

\[f_{i,1}=f_{i-1,1}*\frac{1}{k}(i\geqslant2,f_{1,1}=\frac{1}{k}) \]

然后恍然大悟别人写的是对的,令\(f_{0,0}=1\),然后用上面推出的动态转移方程推得出\(f_{1,1}=\frac{1}{k}\)

所以也可以把我丑的一批的初始化改成这样

f[1][1]=1; F(i,2,M) f[1][i]=f[1][i-1]/k;

\(Code:\)

#include<bits/stdc++.h>
#define ld long double
#define ri register int
#define F(i,l,r) for(ri i=l;i<=r;++i)
using namespace std;
const int N=1005,M=1e4;
ld tmp,f[M+5][N],p;//f[i][j]:前i天只取了j种物品的概率 
int k,q,w;
int main(){;
	scanf("%d%d",&k,&q);
	f[0][0]=1;//f[1][1]=1; F(i,2,M) f[1][i]=f[1][i-1]/k;
	F(j,1,k) F(i,1,M) f[i][j]=(f[i-1][j]*(ld)j/k+f[i-1][j-1]*(ld)(k-j+1)/k);
	while(q--){
		scanf("%Lf",&p); p*=0.0005; w=1;//注意p的类型不能是int,因为要乘0.0005 
		while(f[w][k]<p) ++w;
		//暴力搜就可以没必要二分查,总时间复杂度不超过M*Q,才1e7(注:M的范围是算出来的,当k=1000,p=1000时,w最大也才7000多一点点) 
		printf("%d\n",w);
	}
	return 0;
}

3.总结:方程并不难推,关键是想清楚初始化!!!

END~