版权声明:转吧转吧这条东西只是来搞笑的。。 https://blog.csdn.net/jpwang8/article/details/88976457
Description
n<=2000个人参加比赛
- 两两比一场,比完连个图,边i->j表示i赢了j
- 连完那个图强联通分量缩起来,强连通分量内继续比,即强连通分量递归进行1、2,直到每个强连通分量大小为1
- i<j时i有a/b的概率赢j,问每个人比赛的场数的总和的期望,答案%998244353。
Solution
考虑设f[n]表示n个点的答案,一个套路就是枚举哪些点打成了一个强连通分量。设g[i]表示i个点打成一个强连通分量的概率,h[i,j]表示i个点里面j个点和剩余(i-j)个点打全输的概率,那么
好像挺显然的吧。。
然后考虑g和h怎么求,g可以用1减去不合法的概率,那么就是
一个图不强连通的话我们枚举一个出度为0的连通分量,然后让其余的边都指向它就行了
再看看h怎么求,我们可以讨论一下第i个人放在两个集合中的哪一个,于是就有
这里相当于我们默认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;
}