Description
n<=2000个人参加比赛
- 两两比一场,比完连个图,边i->j表示i赢了j
- 连完那个图强联通分量缩起来,强连通分量内继续比,即强连通分量递归进行1、2,直到每个强连通分量大小为1
- i<j时i有a/b的概率赢j,问每个人比赛的场数的总和的期望,答案%998244353。
n ≤ 2000 n\le2000 n≤2000
Solution
考虑设f[n]表示n个点的答案,一个套路就是枚举哪些点打成了一个强连通分量。设g[i]表示i个点打成一个强连通分量的概率,h[i,j]表示i个点里面j个点和剩余(i-j)个点打全输的概率,那么
f
[
i
]
=
∑
j
=
1
i
g
[
j
]
h
[
i
,
j
]
(
f
[
i
−
j
]
+
f
[
j
]
+
(
j
2
)
+
(
i
−
j
)
j
)
f[i]=\sum_{j=1}^{i}{g[j]h[i,j]\left(f[i-j]+f[j]+\binom{j}{2}+\left(i-j\right)j\right)}
f[i]=j=1∑ig[j]h[i,j](f[i−j]+f[j]+(2j)+(i−j)j)
好像挺显然的吧。。
然后考虑g和h怎么求,g可以用1减去不合法的概率,那么就是
g
[
i
]
=
1
−
∑
j
=
1
i
−
1
g
[
j
]
∗
h
[
i
,
j
]
g[i]=1-\sum_{j=1}^{i-1}{g[j]*h[i,j]}
g[i]=1−j=1∑i−1g[j]∗h[i,j]
一个图不强连通的话我们枚举一个出度为0的连通分量,然后让其余的边都指向它就行了
再看看h怎么求,我们可以讨论一下第i个人放在两个集合中的哪一个,于是就有
h
[
i
,
j
]
=
h
[
i
−
1
,
j
]
⋅
(
1
−
p
)
j
+
h
[
i
−
1
,
j
−
1
]
⋅
p
i
−
j
h[i,j]=h[i-1,j]\cdot{(1-p)}^j+h[i-1,j-1]\cdot{p^{i-j}}
h[i,j]=h[i−1,j]⋅(1−p)j+h[i−1,j−1]⋅pi−j
这里相当于我们默认i个中j个的编号比较大。。
然后我们发现f会转移到自己,那么移项解一个方程就完事了
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (LL i=st;i<=ed;++i)
typedef long long LL;
const int MOD=998244353;
const int ny2=(MOD+2)/2;
const int N=2005;
LL f[N],g[N],h[N][N];
LL ksm(LL x,LL dep) {
LL res=1; x=(x%MOD+MOD)%MOD;
for (;dep;dep>>=1) {
(dep&1)?(res=res*x%MOD):0;
x=x*x%MOD;
}
return res;
}
int main(void) {
int n,a,b; scanf("%d%d%d",&n,&a,&b);
LL p=a*ksm(b,MOD-2)%MOD;
h[1][0]=h[1][1]=1;
rep(i,2,n) {
h[i][0]=1;
rep(j,1,i) {
h[i][j]=(h[i-1][j]*ksm(1+MOD-p,j)%MOD+h[i-1][j-1]*ksm(p,i-j)%MOD)%MOD;
}
}
g[1]=1;
rep(i,2,n) {
rep(j,1,i-1) g[i]=(g[i]+g[j]*h[i][j]%MOD)%MOD;
g[i]=(MOD+1-g[i])%MOD;
}
f[1]=0;
rep(i,2,n) {
f[i]=g[i]*h[i][i]%MOD*i%MOD*(i-1)%MOD*ny2%MOD;
rep(j,1,i-1) {
f[i]=(f[i]+(j*(j-1)%MOD*ny2%MOD+(i-j)*j%MOD+f[j]+f[i-j])%MOD*g[j]%MOD*h[i][j]%MOD)%MOD;
}
f[i]=f[i]*ksm(1-g[i]*h[i][i]%MOD,MOD-2)%MOD;
}
printf("%lld\n", f[n]);
return 0;
}