题解——P3330 [ZJOI2011]看电影
题目传送门
前排广告
省流:
说说我自己这个式子的理解吧。
首先,如果人数多于座位数,即
接着,一个事件的概率=符合条件的情况数/总情况数,那么这个总情况数是非常好考虑的,
然后来看符合条件的情况数,注意到题目中提到“如果当前位置已经有人则向下一个位置以此类推”,而我们并不确定开始选择的位置究竟是什么,不如添加一个
接下来是个人认为最难的地方了,这个
因为这里考虑的是符合条件“都有座位”的情况数,那么就要保证成功,方法是尽可能让每个人向右找座位的容错更高,但显然这个开始点是不确定的,我们连成一个环后,对于每个情况单独考虑,所有没有坐人的地方都可以删去并断开成正常的序列。因此选
对上述解释一句话概括:连成环后忽略编号,哪里为空断开哪里,哪里就是
然而需要一个高精度,因为式子中
其他的看代码就能理解了。
int t;
struct largenum{
int num[10005];
inline void scan(){
char s[10005];
scanf("%s",s+1);
int len=strlen(s+1);
for(int i=len;i>=1;i-=4){
int j=max(i-3,1);
int sum=0;
while(j<=i){
sum=sum*10+(s[j++]-'0');
}
num[++num[0]]=sum;
}
}
inline void print(){
printf("%d",num[num[0]]);
for(int i=num[0]-1;i>=1;i--){
printf("%04d",num[i]);
}
printf(" ");
}
largenum operator *(const largenum &tmp)const{
largenum res;
memset(res.num,0,sizeof(res.num));
res.num[0]=num[0]+tmp.num[0];
for(int i=1;i<=num[0];i++){
for(int j=1;j<=tmp.num[0];j++){
res.num[i+j-1]+=num[i]*tmp.num[j];
res.num[i+j]+=res.num[i+j-1]/base;
res.num[i+j-1]%=base;
}
}
while(res.num[res.num[0]]) res.num[0]++;
while(!res.num[res.num[0]]&&res.num[0]>1) res.num[0]--;
return res;
}
largenum operator *(const int &tmp)const{
largenum res;
memset(res.num,0,sizeof(res.num));
res.num[0]=num[0];
int laz=0;
for(int i=1;i<=res.num[0];i++){
res.num[i]=num[i]*tmp+laz;
laz=res.num[i]/base;
res.num[i]=res.num[i]%base;
}
while(laz){
res.num[++res.num[0]]=laz%base;
laz/=base;
}
while(res.num[res.num[0]]) res.num[0]++;
while(!res.num[res.num[0]]&&res.num[0]>1) res.num[0]--;
return res;
}
int operator %(const int &tmp)const{
int res=0;
for(int i=num[0];i>=1;i--){
res=(res*base+num[i])%tmp;
}
return res;
}
largenum operator /(const int &tmp)const{
largenum res;
memset(res.num,0,sizeof(res.num));
res.num[0]=num[0];
ll laz=0;
for(int i=res.num[0];i>=1;i--){
res.num[i]=(laz*base+num[i])/tmp;
laz=(laz*base+num[i])%tmp;
}
while(!res.num[res.num[0]]&&res.num[0]>1) res.num[0]--;
return res;
}
}ans1,ans2,tmp;
inline largenum q_pow(largenum x,int p){
largenum res;
memset(res.num,0,sizeof(res.num));
res.num[0]=res.num[1]=1;
while(p){
if(p&1){
res=res*x;
}
x=x*x;
p>>=1;
}
return res;
}
inline int gcd(int a,int b){
if(!b) return a;
return gcd(b,a%b);
}
int n,k,m;
int main(){
t=read();
while(t--){
n=read(),k=read();
m=k+1-n;
if(n>k){
printf("0 1\n");
continue;
}
memset(ans1.num,0,sizeof(ans1.num));
memset(ans2.num,0,sizeof(ans2.num));
ans1.num[0]=ans2.num[0]=1;
ans1.num[1]=k+1,ans2.num[1]=k;
ans1=q_pow(ans1,n-1);
ans2=q_pow(ans2,n);
ans1=ans1*m;
//ans1.print();
//ans2.print();
tmp=ans2;
int g=tmp%m;
//printf("\n%d\n",g);
g=gcd(m,g);
//printf("%d\n",g);
ans1=ans1/g;
//printf("%d\n",m);
ans1.print();
ans2=ans2/g;
ans2.print();
printf("\n");
}
return 0;
}