题目链接:牛客练习赛74 E
题目大意
n个点m条边,每条边都有权值 的无向图,k次操作,每次操作是选择两个不同点,然后将这两个点之间的最短路上的所有点都染成黑色,起始点的颜色是ai,黑或者白,问你k次操作后黑色点个数的期望(mod 1023694381)。
思路
求黑色点个数的期望,可以转化成每个点可以染成黑色的概率之和。
选点一共有cnt = n * (n - 1) / 2种情况,该点kk可以染成黑色的情况数就是能够经过该点的最短路的个数,这个最短路可以直接用Floyd预处理出来,判断如果dis[i][j] = dis[i][k]+dis[k][j],那么说明i到j的最短路经过点kk,假设有y条最短路经过点kk。然后求k次操作之后该点能够被染成黑色的概率,正难则反,转换成1 - (不能染成黑色概率)^k,也就是最后对每个点能够染成黑色的概率求和就是期望,如果该点已经是黑色了,那么染黑色概率就是1.
ac代码
#include<bits/stdc++.h>
using namespace std;
#define io cin.tie(0);ios::sync_with_stdio(false);
#define debug(x) cout<<#x<<"="<<x<<endl
#define ll long long
#define rs p<<1|1
#define ls p<<1
#define lowbit(x) x&(-x)
const ll mod = 1023694381;
const int inf = 0x3f3f3f3f;
const ll lnf = 0x3f3f3f3f3f3f;
const int maxn = 505;
const double eps = 1e-10;
ll dis[maxn][maxn];
int a[maxn];
ll _pow(ll a, ll b){
ll ans = 1;
while(b){
if(b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
ll inv(ll a){
return _pow(a, mod - 2);
}
void solve(){
int n, m, k;
cin >> n >> m >> k;
for(int i = 1; i <= n; i ++) cin >> a[i];
for(int i = 1; i <= n; i ++){ //预处理
for(int j = 1; j <= n; j ++){
dis[i][j] = i == j ? 0 : lnf;
}
}
while(m --){
ll x, y, w;
cin >> x >> y >> w;
dis[x][y] = dis[y][x] = w;
}
for(int k = 1; k <= n; k ++){ //跑Floyd最短路
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= n; j ++){
dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
}
}
}
ll x = n * (n - 1) / 2; //选点总数
ll ans = 0;
for(int kk = 1; kk <= n; kk ++){
if(a[kk]) ans = (ans + 1) % mod; //该点已经是黑色,那么概率是1
else {
ll y = 0;
for(int i = 1; i <= n; i ++){
for(int j = i + 1; j <= n; j ++){
if(dis[i][j] == dis[i][kk] + dis[kk][j]) y ++;
}
}
ans = (ans + 1 - _pow((x - y) * inv(x) % mod, k) + mod) % mod; //概率累加
}
}
cout << ans << endl;
}
int main(){
io;
int t = 1;
// cin >> t;
while(t --){
solve();
}
return 0;
}