D. Jon and Orbs (概率dp)
题意:给定 k k k种龙晶, q q q个询问,每天产生一种龙晶,产生每种龙晶概率相等,每个询问给定 p p p,求产生 k k k种龙晶的概率 ≥ ( p − ε ) 2000 \ge \dfrac{(p-\varepsilon)}{2000} ≥2000(p−ε) 的最小天数。
思路:概率 d p dp dp,令 d p [ i ] [ j ] dp[i][j] dp[i][j]表示第 i i i天产生 j j j种龙晶的概率,有转移方程: d p [ i ] [ j ] = d p [ i − 1 ] [ j ] × j k + d p [ i − 1 ] [ j − 1 ] × k − ( j − 1 ) k dp[i][j]=dp[i-1][j]\times \dfrac{j}{k}+dp[i-1][j-1]\times \dfrac{k-(j-1)}{k} dp[i][j]=dp[i−1][j]×kj+dp[i−1][j−1]×kk−(j−1)
因为天数不确定,可开足够大的第一维,或者滚动数组去掉第一维,里层循环倒着转移即可。
然后每次求出第 i i i天的情况后,预处理出 a n s [ p ] ans[p] ans[p]数组。
需要注意的是 d p [ i ] [ 0 ] = ( i = = 0 ) 1 : 0 dp[i][0]=(i==0)1:0 dp[i][0]=(i==0)1:0。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long ll;
const int N=1e3+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb push_back
int k,q;
double dp[N];
int a[N];
int main(){
scanf("%d%d",&k,&q);
dp[0]=1;
for(int i=1,p=1;p<=1000;i++){
for(int j=k;j;j--)
dp[j]=dp[j]*j/k+dp[j-1]*(k-j+1)/k;
while(p<=1000&&dp[k]*2000>=p-1e-7) a[p++]=i;
dp[0]=0;
}
while(q--){
int p;scanf("%d",&p);printf("%d\n",a[p]);
}
return 0;
}