1 条题解
-
0
自动搬运
来自洛谷,原作者为

SoyTony
不要畏惧停滞搬运于
2025-08-24 21:47:47,当前版本为作者最后更新于2022-01-18 14:40:38,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
$$\operatorname{ans}=\dfrac{(k+1)^{n-1}(k+1-n)}{k^n} $$省流:说说我自己这个式子的理解吧。
首先,如果人数多于座位数,即 ,是绝对无法达成“都有座位”的,直接特判输出。
接着,一个事件的概率=符合条件的情况数/总情况数,那么这个总情况数是非常好考虑的, 个人等概率的从 中选取一个,情况数自然是 。
然后来看符合条件的情况数,注意到题目中提到“如果当前位置已经有人则向下一个位置以此类推”,而我们并不确定开始选择的位置究竟是什么,不如添加一个 号椅子并连成一个环,排除其他条件不谈,这 个椅子的情况数为 ,然而是存在重复情况的。例如 与 分别首尾相连成环以后,都是形如 的,也就是说这两种情况是等价的。而成环的连接点有 个,去重后就有 种情况。
接下来是个人认为最难的地方了,这个 是怎么得来的?为什么要连成一个环?
因为这里考虑的是符合条件“都有座位”的情况数,那么就要保证成功,方法是尽可能让每个人向右找座位的容错更高,但显然这个开始点是不确定的,我们连成一个环后,对于每个情况单独考虑,所有没有坐人的地方都可以删去并断开成正常的序列。因此选 个座位后剩下的是 个座位,也就是可以断成 种不同的序列。
对上述解释一句话概括:连成环后忽略编号,哪里为空断开哪里,哪里就是 把椅子。
然而需要一个高精度,因为式子中 与 是无法化简,只要看 和 就可以了,这里会发现,前一个数字是个低精度,而高精取模低精后是低精度,所以麻烦的高精 其实可以拆分成一次高精取模低精和低精 就可以了。
其他的看代码就能理解了。
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; }
- 1
信息
- ID
- 2403
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者