思路:听说是概率dp,表示没接触过,对我来说和普通的dp没什么两样。。。。dp[i][j]表示第i天生产了j种水晶的概率,很明显有dp转移方程dp[i][j]=dp[i-1][j-1]*(k-j+1)/k+dp[i-1][j]*j/k,因为p范围是1~1000,所以跑到超过范围我们就不用跑了,用滑动窗口的技巧记录1~1000的答案,然后就能O(1)查询了。下面给代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<queue>
#include<functional>
typedef long long LL;
using namespace std;
#define maxn 1005
#define ll l,mid,now<<1
#define rr mid+1,r,now<<1|1
#define lson l1,mid,l2,r2,now<<1
#define rson mid+1,r1,l2,r2,now<<1|1
#define inf 0x3f3f3f3f
const int mod = 1e9 + 7;
double dp[10 * maxn][maxn];
int ans[maxn];
int main(){
int k, q;
scanf("%d%d", &k, &q);
dp[0][0] = 1;
for (int i = 1; ; i++){
dp[i][0] = 0;
for (int j = 1; j <= k; j++){
dp[i][j] = dp[i - 1][j - 1] * ((k - j + 1.0) / k) + dp[i - 1][j] * j / k;
}
if (dp[i][k] * 2 >= 1)
break;
}
int pos = 1;
for (int i = 1; i <= 1000; i++){
while (dp[pos][k] * 2000 < i)
pos++;
ans[i] = pos;
}
while (q--){
int p;
scanf("%d", &p);
printf("%d\n", ans[p]);
}
}