牛客练习赛19 托米看电影

时间:2023-02-13 20:18:08

标签 : 状态压缩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;
}