• GYM101623E English Restaurant


    Link

    Solution

    好神啊,完全想不到 ╯︿╰

    计算答案考虑期望的线性性,累加每张桌子的人数期望(取值*概率).

    第i张桌子人数的取值受到一个限制:

     假设第i张桌子的人光临时,第j-1张桌子还没有人坐,而[j,i)的桌子已经被占满,那么人数可能的取值范围就是([c_{j-1}+1,c_i]).

    所以第i张桌子的贡献就是每种[j,i)情况的概率然后乘上(sumlimits_{a=c_{j-1}+1}^{c_i}a).

    考虑做两个dp辅助计算:

    • (f_{i,j}) : 占且仅占[i,j]的桌子的概率
    • (g_{i,j}) : [1,i)中占了j张桌子的概率

    如果求出了(f,g),则答案就是:

    [egin{aligned} ans=sumlimits_{i=1}^nsumlimits_{j=1}^i (frac{1}{G}sumlimits_{a=c_{j-1}+1}^{c_i}a) cdotsumlimits_{k=i-j+1}^tinom{t}{k}(frac{G-c_i}{G})^{t-k} cdot(sumlimits_{l=i-j+1}^kinom{l-1}{i-j}f_{j,i-1}g_{j-1,l-(i-j+1)}(frac{c_i}{G})^{k-l}) end{aligned} ]

    k是枚举t个时刻中共有k个来的人数是(le c_i)的.

    l枚举的是加入第i张桌子后,[1,i]共坐了l张,即在第i张桌子被占之前,[1,i)的桌子中占了l-1张,也可以说是占第i张桌子的团体是k个(le c_i)中的第l个.

    最后(>c_i)的t-k个随便安排,(le c_i)的k-l个在第i张桌子填上之后,所以也是随便安排.

    把l这一维前缀和优化掉就是三方的.

    现在考虑(f,g)怎么算.

    [f_{i,j}=sumlimits_{k=i}^j inom{j-i}{k-i}f_{i,k-1}f_{k+1,j}frac{c_k-c_i-1}{G} ]

    即枚举[i,j]中最后一个占的是第k张.

    [g_{i,j}=sumlimits_{k=i-j}^iinom{j}{i-k}f_{k,i-1}g_{k-1,j-(i-k)} ]

    这个和计算答案的思想类似,枚举的k指第k-1张桌子还没有人坐,而[k,i)的桌子已经被占满.

    感觉动态规划的精髓就在于怎样不重不漏地计算到所有情况怎样把问题规模缩小啊,我大概一辈子也掌握不了精髓QAQ

    Code

    #include<bits/stdc++.h>
    using namespace std;
    #define REP(i,a,b) for(int i=(a),_ed=(b);i<=_ed;++i)
    #define DREP(i,a,b) for(int i=(a),_ed=(b);i>=_ed;--i)
    #define mp(x,y) make_pair((x),(y))
    #define sz(x) (int)(x).size()
    #define pb push_back
    typedef long long ll;
    typedef pair<int,int> pii;
    inline int read(){
        register int x=0,f=1;register char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=0;ch=getchar();}
        while(isdigit(ch)){x=x*10+(ch^'0');ch=getchar();}
        return f?x:-x;
    }
    
    const int N=1e2+5;
    int n,G,t,c[N];
    double C[N][N],f[N][N],g[N][N];
    inline double power(double b,int n){double ans=1;for(;n;n>>=1,b*=b)if(n&1)ans*=b;return ans;}
    inline int sum(int l,int r){return (l+r)*(r-l+1)/2;}
    
    int main(){
        //freopen("in.in","r",stdin);
        REP(i,0,N-1)REP(j,C[i][0]=1,i)C[i][j]=C[i-1][j]+C[i-1][j-1];
        n=read(),G=read(),t=read();
        REP(i,1,n)c[i]=min(read(),G);
        sort(c+1,c+n+1);
        REP(i,1,n+1)f[i][i-1]=1;
        REP(len,1,n)REP(i,1,n-len+1){
    	int j=i+len-1;
    	REP(k,i,j)f[i][j]+=C[j-i][k-i]*f[i][k-1]*f[k+1][j]*(c[k]-c[i-1])/G;
        }
        g[0][0]=1;
        REP(i,1,n)REP(j,0,i-1)REP(k,i-j,i)
    	g[i][j]+=C[j][i-k]*f[k][i-1]*g[k-1][j-(i-k)];
        double ans=0;
        REP(i,1,n)REP(j,1,i){
    	double res=0;
    	REP(k,i-j+1,t){
    	    res=res*c[i]/G+C[k-1][i-j]*g[j-1][(k-1)-(i-j)];
    	    ans+=res*f[j][i-1]*C[t][t-k]*power(1.0*(G-c[i])/G,t-k)*sum(c[j-1]+1,c[i])/G;
    	}
        }
        printf("%.10f
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    Centos 7 LVM xfs文件系统修复
    Feign报错'xx.FeignClientSpecification', defined in null, could not be registered.
    IDEA提示不区分大小写设置
    基于SpringBoot的多模块项目引入其他模块时@Autowired无法注入其他模块stereotype注解类对象的问题解决
    docker安装mysql
    [转]【收藏】用消息队列和消息应用状态表来消除分布式事务
    临时修改当前crontab编辑器
    golang处理 json中非法字符
    nsq里面WaitGroups两种实用的用法
    golang zlib 压缩,解压缩
  • 原文地址:https://www.cnblogs.com/fruitea/p/12637472.html
Copyright © 2020-2023  润新知