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