解析:
听说这是 ZJOI Z J O I D1T1 D 1 T 1 。。。告辞。。。
一看就是一个排列组合有关的问题。
正面硬肝的话,无论是统计合法概率还是非合法概率都显然不可做。。。
考虑新增加一个座位
k+1
k
+
1
那么只要这个座位被坐就是非法情况。
再把头尾连成一个环,保证每一个人都有座位,于是现在有
(k+1)n
(
k
+
1
)
n
种选择方法。
实际上每种选择方法重复了
k+1
k
+
1
次,所以本质不同的方法只有
(k+1)n−1
(
k
+
1
)
n
−
1
种。
还剩下 k−n+1 k − n + 1 个座位,我们只需要令其中某一个的编号为 k+1 k + 1 将它删除,再把环状序列恢复成链状就行了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
#define st static
inline
ll getint(){
re ll num=0;
re char c=gc();
while(!isdigit(c))c=gc();
while(isdigit(c))num=(num<<1)+(num<<3)+(c^48),c=gc();
return num;
}
inline
void outint(ll a){
st char ch[23];
if(a==0)pc('0');
while(a)ch[++ch[0]]=(a-a/10*10)^48,a/=10;
while(ch[0])pc(ch[ch[0]--]);
}
struct Bignum{
int s[2005];
int len;
Bignum(){
memset(s,0,sizeof s);
len=1;
}
void operator =(int x){
Bignum c;
while(x>0){
c.s[c.len-1]=x%10;
c.len++;
x=x/10;
}
while(c.s[c.len-1]==0) c.len--;
*this=c;
}
friend Bignum operator *(Bignum a,Bignum b){
Bignum c;
c.len=a.len+b.len+1;
for(int i=0;i<a.len;i++)
for(int j=0;j<b.len;j++)
{
c.s[i+j]+=a.s[i]*b.s[j];
c.s[i+j+1]+=c.s[i+j]/10;
c.s[i+j]=c.s[i+j]%10;
}
while(!c.s[c.len-1]) c.len--;
return c;
}
friend Bignum operator *(Bignum a,int b){
Bignum c;
c=b;
return a*c;
}
void print()cs{
for(int i=len-1;i>=0;i--)
printf("%d",s[i]);
printf(" ");
}
}a,b;
int A[201],B[201];
int n,k;
int main(){
int T=getint();
while(T--){
n=getint();
k=getint();
if(n>k){
puts("0 1");
continue;
}
a=1,b=1;
memset(A,0,sizeof A);
memset(B,0,sizeof B);
int t=k+1-n;
for(int re i=2;i<=200;++i){
while(t%i==0)++A[i],t/=i;
}
t=k+1;
for(int re i=2;i<=200;++i){
while(t%i==0)A[i]+=n-1,t/=i;
}
t=k;
for(int re i=2;i<=200;++i){
while(t%i==0)B[i]+=n,t/=i;
}
for(int re i=2;i<=200;++i){
int tt=min(A[i],B[i]);
A[i]-=tt;
B[i]-=tt;
}
for(int re i=2;i<=200;++i){
while(A[i])a=a*i,--A[i];
while(B[i])b=b*i,--B[i];
}
a.print(),b.print(),pc('\n');
}
return 0;
}