CF913F Strongly Connected Tournament

Link
\(f_i\)表示\(n\)个点的期望场次。
\(C_{i,j}\)表示从\(i\)个点中选\(j\)个点,这\(j\)个点被其它\(i-j\)个点打败的概率。
\(S_i\)表示\(i\)个点直接形成scc的概率。
先求\(C_{i,j}\),边界为\(C_{i,0}=1\),考虑枚举第\(i\)个点在哪个集合,得到\(C_{i,j}=p^{i-j}C_{i-1,j-1}+(1-p)^jC_{i-1,j}\)
然后求\(S_i\),考虑补集容斥计算不能直接形成scc的概率,枚举拓扑序最大的scc的大小,得到\(S_i=1-\sum\limits_{j=1}^{i-1}S_jC_{i,j}\)
再考虑求\(f_i\),边界为\(f_0=0\),依旧考虑枚举拓扑序最大的scc的大小,得到\(f_i=\sum\limits_{j=1}^iS_jC_{i,j}(f_j+f_{i-j}+j(i-j)+{j\choose 2})\)
注意到\(f_i\)会转移到自己,所以在枚举到\(j=i\)我们先计算\(S_iC_{i,i}{i\choose 2}\),最后再乘上\(\frac1{1-S_iC_{i,i}}\)即可。

#include<cstdio>
const int N=2007,P=998244353;
int f[N],C[N][N],S[N],p[N],q[N];
int inc(int a,int b){return a+=b-P,a+(a>>31&P);}
int dec(int a,int b){return a-=b,a+(a>>31&P);}
int mul(int a,int b){return 1ll*a*b%P;}
int pow(int a,int k){int r=1;for(;k;k>>=1,a=mul(a,a))if(k&1)r=mul(a,r);return r;}
int main()
{
    int n,a,b;scanf("%d%d%d",&n,&a,&b),p[0]=q[0]=1,p[1]=mul(a,pow(b,P-2)),q[1]=dec(1,p[1]);
    for(int i=2;i<=n;++i) p[i]=mul(p[i-1],p[1]),q[i]=mul(q[i-1],q[1]);
    for(int i=0;i<=n;++i) for(int j=C[i][0]=1;j<=i;++j) C[i][j]=inc(mul(p[i-j],C[i-1][j-1]),mul(q[j],C[i-1][j]));
    for(int i=1;i<=n;++i) for(int j=S[i]=1;j<i;++j) S[i]=dec(S[i],mul(S[j],C[i][j]));
    for(int i=1;i<=n;++i)
    {
	f[i]=mul(mul(S[i],C[i][i]),i*(i-1)/2);
	for(int j=1;j<i;++j) f[i]=inc(f[i],mul(mul(S[j],C[i][j]),j*(i-j)+j*(j-1)/2+f[j]+f[i-j]));
	f[i]=mul(f[i],pow(dec(1,mul(C[i][i],S[i])),P-2));
    }
    printf("%d",f[n]);
}
posted @ 2020-04-15 16:01  Shiina_Mashiro  阅读(130)  评论(0)    收藏  举报