转载链接:http://blog.csdn.net/u012015746/article/details/52165631
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5816
个人感想:
…没有做过类似的题目,还能定义为简单状压,实在没想出来,参照大牛的,主要思想是
伤害≥p的牌排列数/所有牌的全排列. (有顺序)
分析:状压+全排列
代码:
/* Author:GavinjouElephant
* Title:
* Number:
* main meanning:
*
*
*
*/
#include <iostream>
using namespace std;
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <sstream>
#include <cctype>
#include <vector>
#include <set>
#include <cstdlib>
#include <map>
#include <queue>
//#include<initializer_list>
//#include <windows.h>
//#include <fstream>
//#include <conio.h>
#define MaxN 0x7fffffff
#define MinN -0x7fffffff
#define Clear(x) memset(x,0,sizeof(x))
const int INF=0x3f3f3f3f;
typedef long long ll;
const int maxn=1<<20;
int T;
int p,n,m;
int dam[25];
ll fact[25];
ll dp[maxn];
void init()
{
fact[0]=1;
for(int i=1;i<=20;i++)
{
fact[i]=fact[i-1]*i;
}
}
int getpop(int x)
{
int res=0;
while(x)
{
if(x&1)res+=1;
x>>=1;
}
return res;
}
bool check(int s)
{
s>>=n;
int res=0;
for(int i=0;i<m;i++)
{
if((s>>i)&1)res+=dam[i];
}
if(res>=p)return true;
return false;
}
ll gcd(ll a,ll b)
{
if(b==0)return a;
return gcd(b,a%b);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("coco.txt","r",stdin);
freopen("lala.txt","w",stdout);
#endif
init();
scanf("%d",&T);
while(T--)
{
memset(dp,0,sizeof(dp));
scanf("%d%d%d",&p,&n,&m);
for(int i=0;i<m;i++)
scanf("%d",&dam[i]);
ll ans=0;
int tot=n+m;
int End=(1<<(n+m))-1;
int getA=(1<<n)-1;
for(int i=0;i<tot;i++)dp[1<<i]=1;
for(int s=0;s<=End;s++)
{
int have=getpop(s);
int left=tot-have;
int haveA=getpop(s&getA);
if(check(s))
{
ans+=dp[s]*fact[left];
continue;
}
if(2*haveA+1-have<=0)continue;
for(int i=0;i<tot;i++)
{
if(!(s&(1<<i)))
{
dp[s|(1<<i)]+=dp[s];
}
}
}
ll k=gcd(ans,fact[n+m]);
printf("%I64d/%I64d\n",ans/k,fact[n+m]/k);
}
return 0;
}