D. Jon and Orbs(概率dp,2200)

题目传送门

题意: 有k种球,每天等概率随机产生一种球,并且收集它。对于q次询问,每次询问一个p,问你至少多少天,你把k种球全部收集到的概率大于等于 p 2000 \frac {p}{2000} 2000p 。( k , q , p < = 1000 k,q,p<=1000 k,q,p<=1000

思路: 我们设 f [ i ] [ j ] f[i][j] f[i][j]为前 i i i天收集了 j j j种蛋的概率,那么 f [ i ] [ j ] f[i][j] f[i][j]就有两种方式转移:

  1. [ i ≥ j ] : f [ i ] [ j ] = f [ i − 1 ] [ j − 1 ] + ( k − j + 1 ) / k [i≥j]:f[i][j]=f[i-1][j-1]+(k-j+1)/k [ij]:f[i][j]=f[i1][j1]+(kj+1)/k
  2. [ i − 1 ≥ j ] : f [ i ] [ j ] = f [ i − 1 ] [ j ] + j / k [i-1≥j]:f[i][j]=f[i-1][j]+j/k [i1j]:f[i][j]=f[i1][j]+j/k

因为 f [ i ] [ j ] f[i][j] f[i][j]只与 f [ i − 1 ] [ j ] f[i-1][j] f[i1][j] f [ i − 1 ] [ j − 1 ] f[i-1][j-1] f[i1][j1]有关,即只与上一层有关,所以我们可以考虑滚动数组优化掉一维.(虽然强行开二维也能过,但是优化后的时空性能都明显优于优化前)

我们用ans[i]表示当p=i时,需要的最小天数。因为 p p p最大是1000,那么当我们将ans[1000]处理完就可以退出预处理了。

代码:

#include<bits/stdc++.h>
#define endl '\n'
#define null NULL
#define ls p<<1
#define rs p<<1|1
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define ll long long
#define int long long
#define lowbit(x) x&-x
#define pii pair<int,int>
#define ull unsigned long long
#define pdd pair<double,double>
#define sz(x) (int)(x).size()
#define all(x) (x).begin(),(x).end()
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
char *fs,*ft,buf[1<<20];
#define gc() (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<20,stdin),fs==ft))?0:*fs++;
inline int read()
{
    
    
    int x=0,f=1;
    char ch=gc();
    while(ch<'0'||ch>'9')
    {
    
    
        if(ch=='-')
            f=-1;
        ch=gc();
    }
    while(ch>='0'&&ch<='9')
    {
    
    
        x=x*10+ch-'0';
        ch=gc();
    }
    return x*f;
}
using namespace std;
const int N=3e6+666;
const int inf=0x3f3f3f3f;
const int mod=998244353;
const double eps=1e-7;
const double PI=acos(-1);

double f[11111];
int ans[N],cnt=0;

signed main()
{
    
    
    int k,q;
    cin>>k>>q;
    f[0]=1;
    for(int i=1;cnt<=1000;i++)
    {
    
    
        for(int j=min(i,k);j>=1;j--)
            f[j]=(f[j-1]*(k-(j-1))+f[j]*j)/k;
        while(i>=k&&f[k]*2000>=cnt)
            ans[cnt++]=i;
        f[0]=0;
    }
    while(q--)
    {
    
    
        int p;cin>>p;
        cout<<ans[p]<<endl;
    }
    return 0;
}

}

猜你喜欢

转载自blog.csdn.net/Joker_He/article/details/110500968
今日推荐