Analysis
真的好棒的一道題啊!!!!
概率即爲合法方案除以總方案
總方案顯然是
合法方案就很妙了
考慮增加一個位置,連成環
那麼所有的方案就都合法了(隨便怎麼選都可以使得每個人找到位置坐下)有種,由於是圓排列,所以要除以
然後再考慮破環成鏈,每一個空位置我們都可以斷開,有種方法
(因爲如果這個位置是空的,那麼一定沒有人跨過它,否則就應該在這個位置優先坐下)
所以最終答案就是
然後就調高精度去吧~
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;
}