有n个人,它们两两进行一场对决,对于一场对局的双方 i , j , i < j i,j,i<j i,j,i<j,i有p的概率会赢,j有(1-p)的概率赢(p对于所有人都是一样的)
能区分出前i名定义为能选择出i个人的一个集合,这个集合中的每个人都击败了集合外的所有人。
求能区分出1~n-1名的概率。
答案对998244353取模
n<=1000000
看到这里,往往会想到多项式
我们考虑选择了j个人,直接计算每个人前面后面的贡献比较难处理,我们考虑先假设这j个人其他每个人都要赢
那么显然最后的概率多乘了 p ( j 2 ) ( 1 − p ) ( j 2 ) p^{j\choose 2}(1-p)^{j\choose 2} p(2j)(1−p)(2j),除掉就好了(如果p=0或者p=1时显然可以直接计算。)
现在每个人的选的贡献就是一定的了,选,就有 ( 1 − p ) i − 1 p n − i (1-p)^{i-1}p^{n-i} (1−p)i−1pn−i,不选就是1。
考虑生成函数,第i个人的生成函数就是 ( 1 − p ) i − 1 p n − i x + 1 (1-p)^{i-1}p^{n-i}x+1 (1−p)i−1pn−ix+1
我们发现这个式子只与i有关,可以写成 ( 1 + k v i x ) (1+kv^ix) (1+kvix)的形式,其中k,v对于所有的i都相同
直接分治NTT两个log显然跑不过去
可以用多项式ln+exp来做,先取个对数,那么每一项就是经典的 l n ( 1 + k x ) ln(1+kx) ln(1+kx)的形式,可以直接拆开来,对于每一个系数求和,类似一个等比数列,然后求出总的再exp回去
然而这个式子也可以倍增,从n推到2n
这样就可以 O ( n log n ) O(n\log n) O(nlogn)解决了
当然这样还是有大概率被卡常数
事实上上面的统统不需要!
考虑DP
设前i个人中选了j个的概率为 F i , j F_{i,j} Fi,j
考虑新加入第i个人
容易得到转移 F i , j = F i − 1 , j ∗ p j + F i − 1 , j − 1 ∗ ( 1 − p ) i − j F_{i,j}=F_{i-1,j}*p^j+F_{i-1,j-1}*(1-p)^{i-j} Fi,j=Fi−1,j∗pj+Fi−1,j−1∗(1−p)i−j
我们也可以考虑新加入第1个人
那么也有转移 F i , j = F i − 1 , j ∗ p i − j + F i − 1 , j − 1 ∗ ( 1 − p ) j F_{i,j}=F_{i-1,j}*p^{i-j}+F_{i-1,j-1}*(1-p)^j Fi,j=Fi−1,j∗pi−j+Fi−1,j−1∗(1−p)j
显然这两个转移是完全等价的
消掉 F i , j F_{i,j} Fi,j,等式就变成了 a x + b y = c x + d y ax+by=cx+dy ax+by=cx+dy的形式
那么 x = d − b a − c y x={d-b\over a-c}y x=a−cd−by
即 F i − 1 , j = p i − j − ( 1 − p ) i − j p j − ( 1 − p ) j F i − 1 , j − 1 F_{i-1,j}={p^{i-j}-(1-p)^{i-j}\over p^j-(1-p)^j}F_{i-1,j-1} Fi−1,j=pj−(1−p)jpi−j−(1−p)i−jFi−1,j−1
又有 F i − 1 , 0 = 1 F_{i-1,0}=1 Fi−1,0=1,这样就可以直接递推出某一行所有的F了!
复杂度仍然是 O ( n log n ) O(n\log n) O(nlogn),但log仅仅是快速幂,时间上完全没有压力。
#include
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define LL long long
#define mo 998244353
#define N 1000005
using namespace std;
LL f[N],js[N],ny[N],cf[N],cf2[N],p;
int n;
LL C(int n,int m)
{
if(n<m) return 0;
return js[n]*ny[m]%mo*ny[n-m]%mo;
}
LL ksm(LL k,LL n)
{
LL s=1;
for(;n;n>>=1,k=k*k%mo) if(n&1) s=s*k%mo;
return s;
}
int main()
{
f[0]=1;
cin>>n>>p;
cf[0]=cf2[0]=1;
fo(i,1,n+1) cf[i]=cf[i-1]*p%mo,cf2[i]=cf2[i-1]*((1-p+mo)%mo)%mo;
if(p*(LL)2%mo==1)
{
js[0]=ny[0]=js[1]=ny[1]=1;
fo(i,2,n)
{
js[i]=js[i-1]*(LL)i%mo;
ny[i]=(-ny[mo%i]*(LL)(mo/i)%mo+mo)%mo;
}
fo(i,2,n) ny[i]=ny[i-1]*ny[i]%mo;
fo(i,1,n-1)
{
printf("%lld ",C(n,i)*ksm(p,(LL)i*(LL)(n-i))%mo);
}
}
else
{
f[0]=1;
fo(i,1,n-1)
{
f[i]=f[i-1]*(cf[n+1-i]-cf2[n+1-i])%mo*ksm((cf[i]-cf2[i]+mo)%mo,mo-2)%mo;
f[i]=(f[i]+mo)%mo;
printf("%lld ",(f[i]+mo)%mo);
}
}
}