CodeForces 261B Maxim and Restaurant

2016暑期集训1-C

CodeForces 261B Maxim and Restaurant

DP,概率期望问题

传送门:HustOJ

传送门:CodeForce


题意

给n个人,以及每个人占据的空间(线性),给一个长度m的桌子。让n个人排队,依次进入桌子就坐,每个人占一定空间。如果剩余空间不能让下一个人进入,那么不再让后面的人进入。这n个人有n!种排队方式,求桌子坐下的人的期望。


思路

思路比较奇特。。。先排序,把人按占用空间由小到大排序。然后dp,前i个人,进去坐了j个,占用空间为k,dp的计算出所有情况。
然后另i等于n,表示前n个人。j从1到n,表示进去了j个人,k从1到m,表示桌子长度不能大于m,进去了j个,占用空间k,组合起来就是所有情况。每个情况对应一种站队方式,前j个人固定,后n-j个人固定。排序后计算可以保证前j个人全能进去,后n-j个人全进不去。每种情况乘以j!和(n-j)!,就是方法数。


代码

注意数据较大,long double,以及输出时用cout,因为不同编译器对它的格式控制不一样

#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
const int MAXN = 55;
//const int oo = 2000000007;
//const long long int loo = 2000000000000000007ll;
typedef long double ll;
ll jc [ MAXN ];
ll dp [ MAXN ] [ MAXN ] [ 2 * MAXN ];//前i个人 进去j个 占空间k 有多少种可能 最后在对这些可能进行全排序 得到总站队数
int a [ MAXN ];
int main ( )
{
    memset ( a , 0 , sizeof ( a ) );
    memset ( dp , 0 , sizeof ( dp ) );
    memset ( jc , 0 , sizeof ( jc ) );
    int n;
    scanf ( "%d" , &n );
    jc [ 0 ] = 1;
    for ( int i = 1; i <= n; i++ )
    {
        jc [ i ] = jc [ i - 1 ] * ( ll ) i;
        scanf ( "%d" , &a [ i ] );
    }
    sort ( a + 1 , a + n + 1 );
    int m;
    scanf ( "%d" , &m );
    dp [ 1 ] [ 0 ] [ 0 ] = 1;//初态 数组a中前1个人 进去0个占空间0 有一种方法
    dp [ 1 ] [ 1 ] [ a [ 1 ] ] = 1;//初态 数组a中前1个人 进去1个占空间a[1] 有一种方法
    for ( int i = 1; i <= n; i++ )
    {
        for ( int j = 0; j <= i; j++ )
        {
            for ( int k = 0; k <= m; k++ )
            {
                dp [ i + 1 ] [ j + 1 ] [ k + a [ i + 1 ] ] += dp [ i ] [ j ] [ k ];
                dp [ i + 1 ] [ j ] [ k ] += dp [ i ] [ j ] [ k ];
            }
        }
    }
    ll res = 0;
    for ( int j = 1; j <= n; j++ )
    {
        for ( int k = 0; k <= m; k++ )
        {
            res += dp [ n ] [ j ] [ k ] * ( jc [ j ] * jc [ n - j ] );
        }
    }
    res = res / jc [ n ];
    cout << res << endl;
    //system ( "pause" );
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值