【CF248E】Piglet's Birthday(动态规划)

【CF248E】Piglet's Birthday(动态规划)

题面

洛谷
CodeForces
翻译:
给定\(n\)个货架,初始时每个上面有\(a[i]\)个蜜罐。
\(q\)次操作,每次操作形如\(u,v,k\),表示从货架\(u\)上任意选择\(k\)个蜜罐试吃(吃过的也还能吃),吃完后把这\(k\)个蜜罐放到\(v\)货架上去。
每次操作完之后回答所有蜜罐都被试吃过的货架数量的期望。

题解

发现没被吃过的数量对于每个货架而言都是单调不增的。
所以考虑没有被吃过的数量,设\(f[i][j]\)表示第\(i\)个货架有\(j\)个蜜罐没有被试吃的概率。
转移的话枚举当前试吃了几个没被吃过的蜜罐用组合数转移即可。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define ll long long
#define MAX 100100
inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
double f[MAX][111],ans;
int n,q,a[MAX],b[MAX];
double C(int n,int m)
{
    if(n<m)return 0;
    double ret=1;
    for(int i=1;i<=m;++i)ret=ret*(1.0*(n-i+1)/i);
    return ret;
}
int main()
{
    n=read();
    for(int i=1;i<=n;++i)a[i]=b[i]=read();
    for(int i=1;i<=n;++i)f[i][a[i]]=1;
    for(int i=1;i<=n;++i)ans+=f[i][0];
    q=read();
    for(int i=1;i<=q;++i)
    {
        int u=read(),v=read(),K=read();ans-=f[u][0];
        for(int j=0;j<=a[u];++j)
        {
            double g=0,tt=C(b[u],K);
            for(int k=0;k<=K;++k)g+=f[u][j+k]*C(j+k,k)*C(b[u]-j-k,K-k)/tt;
            f[u][j]=g;
        }
        b[u]-=K;b[v]+=K;ans+=f[u][0];
        printf("%.10lf\n",ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/cjyyb/p/9403512.html
今日推荐