牛客练习赛19 托米看电影

标签 : 状态压缩dp


题目链接

https://www.nowcoder.com/acm/contest/111/B

分析

  • 用dp[i][j]来表示已经有i个人成功就坐,且坐下的状态为j的二进制.
  • 转移的时候枚举第i个人卡片上的数字

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
#include <stack>
using namespace std;
typedef long long ll;
ll dp[15][1<<16];
vector<int> v[20];
ll gcd(ll a,ll b){
	return b?gcd(b,a%b):a;
}
int main(){
	int t;
	scanf("%d", &t);
	for(int i = 0; i < (1<<15); ++i){
		int j=i,cnt=0;
		while(j) j-=(j&-j),cnt++;
		v[cnt].push_back(i);
	}
	while(t--){
		int n,k;
		scanf("%d%d", &n,&k);
		memset(dp,0,sizeof dp);
		dp[0][0]=1;
		for(int i = 0; i <= n; ++i){
			for(int j = 0; j < (1<<k); ++j){
				if(dp[i][j]==0) continue;
				for(int l = 1; l <= k; ++l){
					for(int p = l-1; p < k; ++p){
						if((j>>p)%2==0){
							dp[i+1][j|(1<<p)]+=dp[i][j];
							break;
						}
					}
				}
			}
		}
		ll sum=0;
		for(auto x:v[n]) sum+=dp[n][x];
		ll tot=1;
		for(int i = 0; i < n; ++i) tot*=k;
		sum=tot-sum;
		ll d=gcd(tot,sum);
		sum/=d;
		tot/=d;
		printf("%lld/%lld\n", sum,tot);
	}
	return 0;
}
posted @ 2018-06-08 13:50  sciorz  阅读(142)  评论(0编辑  收藏  举报