Niuke 练习赛19 B 托米看电影 状压DP

托米老师周末并不用上课,于是他开了一家电影院,他想在电影院来一场邂逅~
有一天,N个女孩子一起去托米家的电影院看电影。她们都订了同一排的票,订完票后还剩下一些时间,她们就去附近购物了,当她们回来的时候,电影已经开始了。门口检票的托米让她们一个接一个找到位置并坐下。
但是,打印电影票的机器坏了。打印出来的座位号不是连续的数字,而是1到K之间的随机整数(说明有重复的),其中K是她们行中的座位总数。
当一个女孩走进一排座位时,座位号从1开始,当她走到她的票号位置上时。如果此时这个座位是空的,她就坐下来。如果它已经被占用,她继续沿着相同的方向走(不能回头),直到她找到第一个空位,然后坐在那里。
所以,有些女孩可能会在没有找到坐下的地方的情况下被排到最后,然后没有位置坐。
现在给你数字n和ķ。
假设每个女孩的票数都在1到K之间,包括1和K之间的数字。每个数字都是随机抽取的,并且抽取是独立的。
当第一个女孩开始寻找她的座位时,也假定整行都是空的。
请你计算至少有一个女孩遭受迎面而来的悲惨命运的概率。

输入描述:

输入的第一行包含一个整数T,表示指定测试用例的数量。
每个测试用例前面都有一个空白行。
每个测试用例由包含两个整数N和K的单行组成

输出描述:

对于每个测试用例输出其概率,用最简分式表示。
示例1

输入

复制
3

1  10

2  3

3  3

输出

复制
0/1
1/9
11/27

说明

在第三种情况下,有33 = 27种可能性。其中,有11名女孩没有位置坐。这11个序列是:133,222,223,232,233,313,322,323,331,332和333。
例如,如果数字序列是322,第一个女孩坐在3座位,第二个女孩坐在2,然后第三个女孩试图坐在2,但是发现座位2和座位3被占用,所以她不能回头。

备注:

T≤100
N,K≤10


题解:

dp[i][s] 表示前i个人构成状态为s的种类数 ->  记录的是满足的种类数(所有女生都有位子坐)

坐满n个人总共的状态个数为tot = Σdp[n][s]  (s是[0,2^k-1]) 

总的可能排列为k^n, 于是不满足条件的种类数为 k^n - tot


或者在状态转移的过程中计算出不满足条件的个数

即当前i个已经不合法了,接下来的n-i个进行全排列


代码:

#include<bits/stdc++.h>
using namespace std;
int dp[11][1<<10];
int main()
{
    int caset;scanf("%d",&caset);
    while(caset--)
    {
        int n,k;
        scanf("%d%d",&n,&k);
        dp[0][0] = 1;
        for(int i=1;i<=n;i++) {
            for(int s=0;s<(1<<k);s++) dp[i][s] = 0;
            for(int s=0;s<(1<<k);s++) if(dp[i-1][s]) {
                for(int j=0;j<k;j++)
                {
                    int to = j;
                    while(s & (1<<to)) ++to;
                    if(to == k) {
                        //printf("s:%d k:%d %d\n",s,k,dp[i-1][s]);
                        //直接计算不合法的种类数
                        //tot += dp[i-1][s] * power(k,n-i);
                        continue;
                    }
                    dp[i][s+(1<<to)] += dp[i-1][s];
                }
            }
        }
        for(int i=0;i<=n;i++) {
            for(int s=0;s<(1<<k);s++) printf("%d ",dp[i][s]);
            printf("\n");
        }
        int ans = 0,tot = 1;
        for(int i=0;i<n;i++) tot *= k;
        for(int s=0;s<(1<<k);s++) ans += dp[n][s];
        ans = tot - ans;
        int gcd = __gcd(ans,tot);
        printf("%d/%d\n",ans/gcd,tot/gcd);
    }   
    return 0; 
}


猜你喜欢

转载自blog.csdn.net/m0_38013346/article/details/80616193
今日推荐