Analysis
真的好棒的一道题啊!!!!
概率即为合法方案除以总方案
总方案显然是
k
n
k^n
kn
合法方案就很妙了
考虑增加一个位置,连成环
那么所有的方案就都合法了(随便怎么选都可以使得每个人找到位置坐下)有
(
k
+
1
)
n
(k+1)^n
(k+1)n种,由于是圆排列,所以要除以
(
k
+
1
)
(k+1)
(k+1)
然后再考虑破环成链,每一个空位置我们都可以断开,有
(
k
+
1
−
n
)
(k+1-n)
(k+1−n)种方法
(因为如果这个位置是空的,那么一定没有人跨过它,否则就应该在这个位置优先坐下)
所以最终答案就是
a
n
s
=
(
k
+
1
)
n
−
1
∗
(
k
+
1
−
n
)
k
n
ans=\frac{(k+1)^{n-1}*(k+1-n)}{k^n}
ans=kn(k+1)n−1∗(k+1−n)
然后就调高精度去吧~
Code
#include<bits/stdc++.h>
#define in read()
#define re register
using namespace std;
inline int read(){
char ch;int f=1,res=0;
while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
while(ch>='0'&&ch<='9'){
res=(res<<1)+(res<<3)+(ch^48);
ch=getchar();
}
return f==1?res:-res;
}
int T,n,k;
int a[205],b[205];
struct BigNumber{
int len,s[505];//s长度
BigNumber(){
memset(s,0,sizeof(s));//!!!!!
len=0;
}
inline void operator = (int x){
BigNumber res;
res.len=0;
while(x){
res.s[++res.len]=x%10;
x/=10;
}
*this=res;
}
inline BigNumber operator *(const BigNumber y){
BigNumber res;
res.len=y.len+len;
for(re int i=1;i<=y.len;++i)
for(re int j=1;j<=len;++j){
res.s[i+j-1]+=y.s[i]*s[j];
res.s[i+j]+=res.s[i+j-1]/10;
res.s[i+j-1]%=10;
}
int &l=res.len;
while(res.s[l]) res.s[l+1]+=res.s[l]/10,res.s[l]%=10,l++;
while(!res.s[l]) l--;
return res;
}
void out(){
for(re int i=len;i>=1;--i) printf("%d",s[i]);
printf(" ");
}
}a1,b1;
void work(){
int t=k;
for(re int i=2;i<=200;++i){
while(t%i==0){
t/=i;
a[i]+=n;
}
}
t=k+1;
for(re int i=2;i<=200;++i){
while(t%i==0){
t/=i;
b[i]+=n-1;
}
}
t=k+1-n;
for(re int i=2;i<=200;++i){
while(t%i==0){
t/=i;
b[i]++;
}
}
for(re int i=2;i<=200;++i){
int hh=min(a[i],b[i]);
a[i]-=hh;b[i]-=hh;
}
a1=1;b1=1;
for(re int i=2;i<=200;++i){
BigNumber tmp;
tmp=i;
while(a[i]){
a1=a1*tmp;
a[i]--;
}
}
for(re int i=2;i<=200;++i){
BigNumber tmp;
tmp=i;
while(b[i]){
b1=b1*tmp;
b[i]--;
}
}
}
int main(){
scanf("%d",&T);
while(T--){
n=in;k=in;
if(k<n){
printf("0 1\n");
continue;
}
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
work();
b1.out();
a1.out();
printf("\n");
}
return 0;
}