【2025.10.10NOIP】概率 (pr)题解
题目描述
你有一个随机数生成器,每次会均匀随机地生成一个 [0,m] 之间的整数。你用这个随机生成器生成了 2n 个整数,你想知道你生成的前 n 个整数的和比后 n 个整数的和大的概率是多少。你只需求出这个概率对质数 P 取模后的结果即可。
对质数 P 取模的定义:对于一个有理数,将其写成既约分数 a/b,如果 b 不是 P 的倍数,可以证明存在唯一的整数 0≤x<P 满足 xb≡a(modP),定义这个 x 就是 a/b 对 P 取模的结果。
可以证明本题的答案概率一定是一个有理数,且约分后分母一定不是题目数据范围中 P 的倍数。
输入
从文件 pr.in 中读入数据。
在文件 pr.in 中读入。
每个测试点有多组询问,但用的都是同一个模数。
第一行一个整数 P 表示这个测试点所用模数。
第二行一个整数 T 表示询问组数。
接下来 T 行每行两个整数分别表示每组询问的 n 和 m。
输出
输出到文件 pr.out 中。
在文件 pr.out 中输出。
共 T 行,每行一个整数表示答案。
样例数据
输入 #1 复制
998244353 5 1 2 3 4 25 25 114 514 1919 810
输出 #1 复制
332748118 675356228 865314458 846704265 499065697
数据范围限制
本题共有 10 个测试点,每个测试点 10 分。
对于所有测试点,保证 1≤T,n,m≤2000,108≤P≤109,且 P 是质数。
• 对于测试点 1,有 1≤T,n,m≤5。
• 对于测试点 2,3,有 1≤T,n,m≤15。
• 对于测试点 4,5,有 1≤T,n,m≤50。
• 对于测试点 6,7,有 1≤T,n,m≤200。
• 对于测试点 8,9,有 1≤T,n,m≤1000。
• 对于测试点 10,无特殊限制。
提示
样例 1 解释
对于第一组询问,满足条件当且仅当生成的 2n 个整数为 [2,0],[2,1],[1,0] 三种情况
之一,概率为 3/(m+1)2n=1/3,对 998244353 取模后的结果为 332748118。
思路
数学。
代码见下
#include<bits/stdc++.h>
using namespace std;
long long p,t,n,m,f[55][5505],opd=0,jx[5000006],jx2[5000006],op=0,kl=0,lk=0,bz,oj;
long long pow2(long long a1,long long b1){
long long kk1=1;
a1%=p;
while(b1){
if(b1%2==1){
kk1=kk1*a1%p;
}
b1/=2;
a1=a1*a1%p;
}
return kk1;
}
long long C(long long a1){
return jx[2*n]*jx2[a1]%p*jx2[2*n-a1]%p;
}
long long C2(long long a1,long long b1){
if(a1>=b1){
return jx[a1]*jx2[b1]%p*jx2[a1-b1]%p;
}
else{
return 0;
}
}
int main(){
freopen("pr.in","r",stdin);
freopen("pr.out","w",stdout);
cin>>p;
cin>>t;
jx[0]=1;
jx2[0]=pow2(jx[0],p-2);
for(int i=1;i<=5000000;i++){
jx[i]=(jx[i-1]*i)%p;
jx2[i]=pow2(jx[i],p-2);
}
while(t--){
cin>>n>>m;
op=-1;
lk=kl=bz=oj=0;
for(int i=0;i<=2*n;i++){
op*=-1;
kl=op*C(i)%p;
kl=kl*C2(n*m-(m+1)*i+2*n-1,2*n-1)%p;
lk=(lk+kl)%p;
}
//cout<<lk<<endl;
lk=(lk+p)%p;
bz=(pow2(m+1,2*n)-lk+p)%p;
oj=pow2(pow2(m+1,p-2),2*n)*pow2(2,p-2)%p;
//cout<<oj<<endl;
cout<<(bz*oj)%p<<endl;
}
return 0;
}

浙公网安备 33010602011771号