Description
有一天, 个女孩子一起去托米家的电影院看电影。她们都订了同一排的票,订完票后还剩下一些时间,她们就去附近购物了,当她们回来的时候,电影已经开始了。门口检票的托米让她们一个接一个找到位置并坐下。
但是,打印电影票的机器坏了。打印出来的座位号不是连续的数字,而是 到 之间的随机整数(说明有重复的),其中 是她们行中的座位总数。
当一个女孩走进一排座位时,座位号从 开始,当她走到她的票号位置上时。如果此时这个座位是空的,她就坐下来。如果它已经被占用,她继续沿着相同的方向走(不能回头),直到她找到第一个空位,然后坐在那里。
所以,有些女孩可能会在没有找到坐下的地方的情况下被排到最后,然后没有位置坐。
现在给你数字 和 。
假设每个女孩的票数都在 到 之间,包括 和 之间的数字。每个数字都是随机抽取的,并且抽取是独立的。
当第一个女孩开始寻找她的座位时,也假定整行都是空的。
请你计算至少有一个女孩遭受迎面而来的悲惨命运的概率。
Input
输入的第一行包含一个整数 ,表示指定测试用例的数量。
每个测试用例前面都有一个空白行。
每个测试用例由包含两个整数 和 的单行组成
Output
对于每个测试用例输出其概率,用最简分式表示。
Sample Input
3
1 10
2 3
3 3
Sample Output
0/1
1/9
11/27
Solution
状压
,以
表示
个人,还有
状态的座位没有被选,最终至少有一个女孩没有座位的方案数,枚举第
个女孩的票号
,如果
中第
个位置为
,那么直接转移
如果
中第
个位置为
,那么考虑第
个位置之后是否还有
,如果没有
说明第
个女孩没有座位,剩下
个女孩随便选,直接有转移
如果
位置之后有一个位置
为
,那么第
个女孩只能坐在第
个位置,此时又转移
记忆化搜索即可,答案即为
,时间复杂度
Code
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
int T,n,k;
ll dp[11][(1<<10)+5],f[11];
ll gcd(ll a,ll b)
{
return b?gcd(b,a%b):a;
}
ll dfs(int n,int S)
{
if(dp[n][S]!=-1)return dp[n][S];
if(n==0)return dp[n][S]=0;
if(S==0)return dp[n][S]=f[n];
dp[n][S]=0;
for(int i=0;i<k;i++)
if(!((S>>i)&1))
{
int j=i+1;
for(;j<k;j++)
if((S>>j)&1)break;
if(j<k)dp[n][S]+=dfs(n-1,S^(1<<j));
else dp[n][S]+=f[n-1];
}
else dp[n][S]+=dfs(n-1,S^(1<<i));
return dp[n][S];
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&k);
f[0]=1;
for(int i=1;i<=n;i++)f[i]=f[i-1]*k;//k^i
int K=1<<k;
memset(dp,-1,sizeof(dp));
ll p=dfs(n,K-1),q=f[n];
ll g=gcd(p,q);
printf("%lld/%lld\n",p/g,q/g);
}
return 0;
}