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