1. 程式人生 > >Newcoder 111 B.托米看電影(狀壓)

Newcoder 111 B.托米看電影(狀壓)

Description

有一天, n n 個女孩子一起去托米家的電影院看電影。她們都訂了同一排的票,訂完票後還剩下一些時間,她們就去附近購物了,當她們回來的時候,電影已經開始了。門口檢票的托米讓她們一個接一個找到位置並坐下。

但是,列印電影票的機器壞了。打印出來的座位號不是連續的數字,而是 1

1 k k 之間的隨機整數(說明有重複的),其中 k k 是她們行中的座位總數。

當一個女孩走進一排座位時,座位號從 1

1 開始,當她走到她的票號位置上時。如果此時這個座位是空的,她就坐下來。如果它已經被佔用,她繼續沿著相同的方向走(不能回頭),直到她找到第一個空位,然後坐在那裡。

所以,有些女孩可能會在沒有找到坐下的地方的情況下被排到最後,然後沒有位置坐。

現在給你數字 n n k

k

假設每個女孩的票數都在 1 1 k k 之間,包括 1 1 k k 之間的數字。每個數字都是隨機抽取的,並且抽取是獨立的。

當第一個女孩開始尋找她的座位時,也假定整行都是空的。

請你計算至少有一個女孩遭受迎面而來的悲慘命運的概率。

Input

輸入的第一行包含一個整數 T T ,表示指定測試用例的數量。

每個測試用例前面都有一個空白行。

每個測試用例由包含兩個整數 n n k k 的單行組成

( T 100 , n , k 10 ) (T\le 100,n,k\le 10)

Output

對於每個測試用例輸出其概率,用最簡分式表示。

Sample Input

3

1 10

2 3

3 3

Sample Output

0/1
1/9
11/27

Solution

狀壓 D P DP ,以 d p [ i ] [ S ] dp[i][S] 表示 i i 個人,還有 S S 狀態的座位沒有被選,最終至少有一個女孩沒有座位的方案數,列舉第 i i 個女孩的票號 j j ,如果 S S 中第 j j 個位置為 1 1 ,那麼直接轉移
d p [ i ] [ S ] + = d p [ i + 1 ] [ S 2 j ] dp[i][S]+=dp[i+1][S-2^j]
如果 S S 中第 j j 個位置為 0 0 ,那麼考慮第 j j 個位置之後是否還有 1 1 ,如果沒有 1 1 說明第 i i 個女孩沒有座位,剩下 i 1 i-1 個女孩隨便選,直接有轉移
d p [ i ] [ S ] + = k i 1 dp[i][S]+=k^{i-1}
如果 j j 位置之後有一個位置 k k 1 1 ,那麼第 i i 個女孩只能坐在第 k k 個位置,此時又轉移
d p [ i ] [ S ] + = d p [ i + 1 ] [ S 2 k ] dp[i][S]+=dp[i+1][S-2^k]
記憶化搜尋即可,答案即為 d p [ n ] [ 2 k 1 ] k n \frac{dp[n][2^k-1]}{k^n} ,時間複雜度 O ( n k 2 k ) O(n\cdot k\cdot 2^k)

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;
}