(HDU 5816)2016 Multi-University Training Contest 7 Hearthstone (状压DP、搜索)

思路

能够赢的状态有:
1. 抽一张B就赢
2. 抽一定数量的A、配合B

Tip:
1. 如果造成的伤害已经 p ,那么就直接乘上剩下的全排列即可
2. 从已经抽了的牌数可以推出能够再抽的牌数:

leftCard=usedAusedB+1

从小到大枚举状态S,判断S是否合法,即S的方案数不为0且还能摸牌,然后通过S去更新S+i(i∉S,即后续摸牌状态)状态的值

代码

#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define rep(i,a,b) for(int i=a;i<b;i++)
#define debug(a) printf("a =: %d\n",a);
const int INF=0x3f3f3f3f;
const int maxn=1e3+50;
const int Mod=1000000007;
const double PI=acos(-1);
typedef long long ll;
using namespace std;

int n,p,a,b,k;
ll dp[1<<22];
int sb[100];
ll jc[100];
ll fz;
void init(){
    jc[0]=jc[1]=1;
    for(int i=2;i<=20;i++){
        jc[i]=jc[i-1]*i;
    }
}

inline bool getBit(int x,int i){
    return (x>>i)&1;
}
int countBit(int x,int n){
    int ret=0;
    for(int i=0;i<n;i++){
        if (x&(1<<i)) ret++;
    }
    return ret;
}

void solve(){
    mem(dp,0);
    dp[0]=1;
    for(int i=0;i<(1<<k);i++){
        if (dp[i]==0) continue;
        int cb=0,ca=0,sum=0;
        for(int j=a;j<k;j++){
            if (getBit(i,j)){
                cb++; sum+=sb[j];
            }
        }
        //不用再抽牌 
        if (sum>=p) continue;

        ca=countBit(i,a);

        //没有后续状态 : AABBB  ABB B
        if (ca-cb+1<=0) continue;

        for(int j=0;j<k;j++){
            if (!getBit(i,j)){
                dp[i^(1<<j)]+=dp[i];
            }
        }
    }

    for(int i=0;i<(1<<k);i++){
        if (dp[i]==0) continue;
        int cb=0,ca=0,sum=0;
        for(int j=a;j<k;j++){
            if (getBit(i,j)){
                cb++; sum+=sb[j];
            }
        }

        ca=countBit(i,a);

        if (sum>=p) fz+=jc[k-ca-cb]*dp[i];
    }
}
int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
    #endif

    init();
    int T; scanf("%d",&T);
    for(int cs=1;cs<=T;cs++){
        scanf("%d %d %d",&p,&a,&b);
        k=a+b;
        for(int i=a;i<k;i++){
            scanf("%d",sb+i);
        }
        fz=0;
        solve();
        ll fm=jc[k];
        if (fz==0) printf("0/1\n");
        else {
            ll gc=__gcd(fz,fm);
            printf("%lld/%lld\n",fz/gc,fm/gc);
        }

    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值