sgu285:What? Where? When?(状压dp)

题目大意:
       又是一个游戏。这个游戏有两方 A,B A 方问问题,B方答问题,每个问题都有一个答对的概率,答对了 A 的积分+1,否则 B 的积分+1。将一个圆 13 等分,逆时针编号, 112 每部分上都放了一个信封,每个信封内有一个问题。第 13 部分放了一个空信封,如果抽到了该部分,那么从 n 个在线问题中随机抽一个问。圆上有一个转盘,它的指针随机地指向一个部分,如果该部分的信封已经用过了,那么沿着逆时针一直转到一个没用过的信封。求最后比分为6:0,6:1,6:2,6:3,6:4,6:5,5:6,4:6,3:6,2:6,1:6,0:6的概率。

分析:
       就是一个裸的状压概率 dp fs,i,j 表示选了的状态为 s ,双方积分为i:j的概率。

AC code:

#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <string>
#include <sstream>
#include <iostream>
#include <map>
#include <set>
#include <list>
#include <stack>
#include <queue>
#include <vector>
#define pb push_back
#define mp make_pair
#define get(x, i) (((x)>>(i-1))&1) 
typedef long long LL;
typedef double DB;
typedef long double LD;
using namespace std;

int n;
DB p[14], sum;
DB f[7][7][1<<13];
DB tp[1<<13][14];
DB ans[7][7];

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
    #endif

    cin >> n;
    for(int i = 1; i <= 12; ++i)
        cin >> p[i];
    DB x, sum = 0;
    for(int i = 1; i <= n; ++i)
        cin >> x, sum += x;
    p[13] = sum/n;
    for(int i = 0; i < (1<<13)-1; ++i)
    {
        int now = 1, s, cnt = 0;
        while(get(i, now)) now++;
        s = now, now = now%13+1;
        while(true)
        {
            cnt = 1;
            while(get(i, now)) now = now%13+1, cnt++;
            tp[i][now] = 1.0*cnt/13;
            if(now == s) break;
            now = now%13+1;
        }
    }
    f[0][0][0] = 1;
    for(int i = 0; i <= 6; ++i)
        for(int j = 0; j <= 6; ++j)
            if(i != 6 && j != 6)
                for(int s = 0; s < (1<<13); ++s)
                    if(f[i][j][s] > 0)
                        for(int l = 1; l <= 13; ++l)
                            if(!get(s, l))
                            {
                                f[i+1][j][s|(1<<(l-1))] += f[i][j][s]*tp[s][l]*p[l];
                                f[i][j+1][s|(1<<(l-1))] += f[i][j][s]*tp[s][l]*(1-p[l]);
                            }
    for(int i = 0; i <= 6; ++i)
        for(int j = 0; j <= 6; ++j)
            for(int s = 0; s < (1<<13); ++s)
                ans[i][j] += f[i][j][s];
    for(int i = 0; i <= 5; ++i)
        printf("%.3lf\n", ans[6][i]);
    for(int i = 5; i >= 0; --i)
        printf("%.3lf\n", ans[i][6]);

    #ifndef ONLINE_JUDGE
    fclose(stdin);
    fclose(stdout);
    #endif
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值