时间限制:1秒 内存限制:64M
【问题描述】
到了难得的假期,小白班上组织大家去看电影。但由于假期里看电影的人太多,很难做到让全班看上同一场电影,最后大家在一个偏僻的小胡同里找到了一家电影院。但这家电影院分配座位的方式很特殊,具体方式如下:
1.电影院的座位共有K个,并被标号为1…K,每个人买完票后会被随机指定一个座位,具体来说是从1…K中等可能的随机选取一个正整数,设其为L。
2.如果编号L的座位是空位,则这个座位就分配给此人,否则将L加一,继续前面的步骤。
3.如果在第二步中不存在编号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
【数据范围】
对于20%的数据 N,K<=10
对于100%的数据 T<=50,N,K<=200
【来源】
bzoj 2227
这个数据范围不是递推就是推公式.(反正要推,不是电脑推就是人推)
分母不说了,k^n(每个人选一个选)。
分子现在就是重点了。n>k肯定不管,直接就是0了(除非叠罗汉)。
我当时也是直接打了个暴力然后看数据推出来是(k+1)^(n-1)*(k+1-n)的。
现在我们就分析n<=k的情况。我们先搞个环出来,虚构一个点,到这个点就又轮回到1去(超级点),这样就有(k+1)^n种选法,但由于是环所以去重后其实只有(k+1)^(n-1)(因为方案数种每种有k+1个,以每个点开头都有一个)。现在没有重复情况了,我们只要删除一个没人的点就可以破环了,所以最后要乘以没人的位置数(k+1-n)。
这道题最后主要是高精度有毒,当你发现辛辛苦苦推出公式了,但高精度打错了。(本OIer亲身经历)
代码如下:
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
int n,m;
int a[205],b[205];
struct shu
{
int len,s[2005];
shu ()
{
memset(s,0,sizeof(s));
len=1;
}
void operator =(int x)
{
shu 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;
}
void out()
{
for(int i=len-1;i>=0;i--)
printf("%d",s[i]);
printf(" ");
}
friend shu operator *(shu a,shu b)
{
shu 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 shu operator *(shu a,int b)
{
shu c;
c=b;
return a*c;
}
}a1,b1;
void work()
{
int t=m;
for(int i=2;i<=t;i++)
{
while(t%i==0)
{
t/=i;
a[i]+=n;
}
}
t=m+1;
for(int i=2;i<=t;i++)
{
while(t%i==0)
{
t/=i;
b[i]+=n-1;
}
}
t=m+1-n;
for(int i=2;i<=t;i++)
{
while(t%i==0)
{
t/=i;
b[i]++;
}
}
for(int i=1;i<=200;i++)
{
int k=min(a[i],b[i]);
a[i]-=k;
b[i]-=k;
}
a1=1,b1=1;
for(int i=1;i<=200;i++)
while(a[i])
{
a1=a1*i;
a[i]--;
}
for(int i=1;i<=200;i++)
while(b[i])
{
b1=b1*i;
b[i]--;
}
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
if(m<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;
}