[JZOJ6067]【NOI2019模拟2019.3.18】More?More!【DP】【数学】

Description

有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

Solution

看到这里,往往会想到多项式
我们考虑选择了j个人,直接计算每个人前面后面的贡献比较难处理,我们考虑先假设这j个人其他每个人都要赢

那么显然最后的概率多乘了 p ( j 2 ) ( 1 − p ) ( j 2 ) p^{j\choose 2}(1-p)^{j\choose 2} p(2j)(1p)(2j),除掉就好了(如果p=0或者p=1时显然可以直接计算。)

现在每个人的选的贡献就是一定的了,选,就有 ( 1 − p ) i − 1 p n − i (1-p)^{i-1}p^{n-i} (1p)i1pni,不选就是1。
考虑生成函数,第i个人的生成函数就是 ( 1 − p ) i − 1 p n − i x + 1 (1-p)^{i-1}p^{n-i}x+1 (1p)i1pnix+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=Fi1,jpj+Fi1,j1(1p)ij

我们也可以考虑新加入第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=Fi1,jpij+Fi1,j1(1p)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=acdby
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} Fi1,j=pj(1p)jpij(1p)ijFi1,j1

又有 F i − 1 , 0 = 1 F_{i-1,0}=1 Fi1,0=1,这样就可以直接递推出某一行所有的F了!

复杂度仍然是 O ( n log ⁡ n ) O(n\log n) O(nlogn),但log仅仅是快速幂,时间上完全没有压力。

Code

#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);
		}
	}
}

你可能感兴趣的:(题解,---DP,---计数,————概率与期望)