题目描述
到了难得的假期,小白班上组织大家去看电影。但由于假期里看电影的人太多,很难做到让全班看上同一场电影,最后大家在一个偏僻的小胡同里找到了一家电影院。但这家电影院分配座位的方式很特殊,具体方式如下:
- 电影院的座位共有K个,并被标号为1…K,每个人买完票后会被随机指定一个座位,具体来说是从1…K中等可能的随机选取一个正整数,设其为L。
- 如果编号L的座位是空位,则这个座位就分配给此人,否则将L加一,继续前面的步骤。
- 如果在第二步中不存在编号L的座位,则该人只能站着看电影,即所谓的站票。
小白班上共有N人(包括小白自己),作为数学爱好者,小白想知道全班都能够有座位的概率是多少。
输入格式
输入文件第一行有且只有一个正整数T,表示测试数据的组数。
第2~T+1行,每行两个正整数N,K,用单个空格隔开,其含义同题目描述。
输出格式
输出文件共包含T行。
第i行应包含两个用空格隔开的整数A,B,表示输入文件中的第i组数据的答案为A/B。(注意,这里要求将答案化为既约分数)
样例
样例输入
3
1 1
2 1
2 2
样例输出
1 1
0 1
3 4
数据范围与提示
对于100%的数据 T<=50,N,K<=200
题解
可以在k+1的位置加一个座位再把它连成一个环,情况数便为(k+1)^n;
因为是个环所以去重为(k+1)^(n-1);
最后拆环并且首位不能有人,ans=(k+1)^(n-1)*(k-n+1);
最后的概率便是 p=ans/k^n;
输出要用分数形式,直接上高精乘,我们观察式子发现上下最多有可能是(k-n+1)和k^n有公因子,所以跑gcd不断除出去。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
#include<bits/stdc++.h> #define ll long long using namespace std; ll T,t,n,k,A,B,C,sum[3][10000],len[3]; ll gcd(ll x,ll y) { return y==0?x:gcd(y,x%y); } void X(ll x,ll h) { ll y=0; for(int i=0;i<=len[h];i++) { ll z=sum[h][i]*x+y; sum[h][i]=z%10; y=z/10; } while(y) { sum[h][++len[h]]=y%10; y/=10; } } void print(ll h) { for(int i=len[h];i>=0;i--) printf("%lld",sum[h][i]); } void work() { memset(len,0,sizeof(len)); memset(sum,0,sizeof(sum)); sum[1][0]=1; sum[2][0]=1; scanf("%lld%lld",&n,&k); if(n>k) { puts("0 1"); return; } C=k-n+1; B=n; while(C!=1&&B>0) { ll o=gcd(C,k); B--; X(k/o,2); C/=o; } X(C,1); for(int i=1;i<=n-1;i++) X(k+1,1); for(int i=1;i<=B;i++) X(k,2); print(1); printf(" "); print(2); puts(""); } int main() { scanf("%lld",&T); while(T--) work(); return 0; }