题解 CF913F【Strongly Connected Tournament】
$\text{update 2022.2.21}$:修正一处笔误。
题意
给你 $n$ 个点,其中对于所有的 $i,j(i<j)$连有一条的有向边,其中有 $p=\dfrac a b$ 的概率为 $i$ 连向 $j$。
对这张完全图缩点,并对于每个强连通分量重复执行以上操作直至只剩一个点。
求期望的连边数,对 $998244353$ 取模。
$n\le 2000$。
思路
nb dp 题。
我们设 $dp_i$ 表示 $i$ 个点时的期望答案。
考虑枚举最弱的强联通分量的大小,则对于这个强联通分量里的点已经构成了一张完全图,并且其它的点都打赢过这个强联通分量里的点。换句话说,如果这个强联通分量大小为 $j$,则已经连了 $j(i-j)+\dfrac{j(j-1)}2$ 条边了。
考虑需要算出 $i$ 个点组成强联通图的概率与 $i$ 个点都打赢了其中 $j$ 个点的概率,不妨分别设其为 $c_i,d_{i,j}$。
考虑一次转移,还需要在强联通分量内部和外部递归处理,列出转移方程:
$$dp_i=\sum_{j=1}^ic_jd_{i,j}\left(j(i-j)+\dfrac {j(j-1)}2+dp_j+dp_{i-j}\right)$$
但是我们发现当 $i=j$ 即这个图自己构成一个强联通分量时,$dp_i$ 会转移到自己,考虑变个形:
$$dp_i=\dfrac{\sum_{j=1}^{i-1}\left[c_jd_{i,j}\left(j(i-j)+\dfrac {j(j-1)}2+dp_j+dp_{i-j}\right)\right]+c_id_{i,i}\dfrac {i(i-1)}2}{1-c_id_{i,i}}$$
现在需要算出 $c$ 和 $d$。
考虑只要图中没有点被其它点都吊打的情况它就是强联通图,$c$ 的转移十分简单:
$$c_i=1-\sum_{j=1}^{i-1}c_jd_{i,j}$$
对于 $d$,考虑新加入一个点,如果它是输的那 $j$ 个中的一个,则它要输给 $i-j$ 个点,否则它要赢 $j$ 个点。转移也比较简单(注意边的方向与编号大小的关系):
$$d_{i,j}=(1-p)^jd_{i-1,j}+p^{i-j}d_{i-1,j-1}$$
时间复杂度 $\Theta(n^2)$。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//by cyffff
}
const int N=2000+10,mod=998244353;
inline int qpow(int x,int y){
int res=1;
while(y){
if(y&1) res=1ll*res*x%mod;
x=1ll*x*x%mod;
y>>=1;
}
return res;
}
int n,p,c[N],d[N][N],dp[N];
int main(){
n=read();
int a=read(),b=read();
p=1ll*a*qpow(b,mod-2)%mod;
d[1][0]=d[1][1]=1;
for(int i=2;i<=n;i++){
d[i][0]=1;
for(int j=1;j<=i;j++)
d[i][j]=(1ll*d[i-1][j]*qpow(mod+1-p,j)+1ll*d[i-1][j-1]*qpow(p,i-j))%mod;
}
for(int i=1;i<=n;i++){
int res=0;
for(int j=1;j<i;j++)
res=(res+1ll*c[j]*d[i][j])%mod;
c[i]=((1-res)%mod+mod)%mod;
}
for(int i=1;i<=n;i++){
int res=0;
for(int j=1;j<i;j++){
int tmp=(dp[j]+dp[i-j])%mod;
tmp=(tmp+1ll*j*(i-j))%mod;
tmp=(tmp+1ll*j*(j-1)/2)%mod;
res=(res+1ll*c[j]*d[i][j]%mod*tmp)%mod;
}
res=(res+1ll*c[i]*d[i][i]%mod*(i*(i-1)/2))%mod;
dp[i]=1ll*res*qpow(mod+1-1ll*c[i]*d[i][i]%mod,mod-2)%mod;
}
write(dp[n]);
flush();
}
再见 qwq~

浙公网安备 33010602011771号