题目大意:
给你一张n个白点m边的带权无向图。一次你可以选择两个点,将他们之间的最短路上的点都染成黑色(如有多条,都染成黑色).问你k次之后期望有多少个点染成黑色.
n
,
m
≤
500
,
k
,
w
≤
1
e
9
n,m \leq 500 , k,w\leq 1e9
n,m≤500,k,w≤1e9
题目思路:
这个题目关键要知道两个点:
1.期望的独立性:一个点是否变黑色与其他点没有关系,并且两次染色之间也没有互相影响,所以我们可以对每个点进行独立计算.
2.期望=概率:由于点之间独立,所以我们就是求每个点在k次之后变成黑色的期望的累和.由于这里的期望不带权值,所以期望就是概率..然后正难则反,我们只要求[一次不变黑]的概率的 k k k次方即可.
那么我们先floyd跑一跑最短路,然后求每个点有多少条最短路经过.之后 O ( n ) O(n) O(n)计算即可.
AC代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 500 + 5;
const int mod = 1023694381;
ll a[maxn] , dp[maxn][maxn] , cnt[maxn];
ll ksm (ll a , ll b){ ll ans = 1 , base = a;
while (b){if (b & 1) ans = ans * base % mod;b >>= 1;base = base * base % mod;}return ans;}
int main()
{
ios::sync_with_stdio(false);
ll n , m , k; cin >> n >> m >> k;
for (int i = 1 ; i <= n ; i++){
cin >> a[i];
}
memset(dp , -1 , sizeof dp);
for (int i = 1 ; i <= n ; i++){
dp[i][i] = 0;
}
for (int i = 1 ; i <= m ; i++){
int x , y , z; cin >> x >> y >> z;
dp[x][y] = dp[y][x] = z;
}
for (int k = 1 ; k <= n ; k++){
for (int i = 1 ; i <= n ; i++){
for (int j = 1 ; j <= n ; j++){
if (dp[i][k] == -1 || dp[k][j] == -1) continue;
if (dp[i][j] == -1 || dp[i][j] > dp[i][k] + dp[k][j])
dp[i][j] = dp[i][k] + dp[k][j];
}
}
}
for (int k = 1 ; k <= n ; k++){
for (int i = 1 ; i <= n ; i++){
for (int j = 1 ; j <= n ; j++){
if (i == j) continue;
if (dp[i][j] == dp[i][k] + dp[k][j])
cnt[k]++;
}
}
}
ll ans = 0 , g = n * (n - 1);
ll inv = ksm(g , mod - 2);
for (int i = 1 ; i <= n ; i++){
if (a[i] == 1) {
ans++;
continue;
}
ll res = (g - cnt[i]) * inv % mod;
res = ksm(res , k);
res = (1 - res + mod) % mod;
ans = (ans + res) % mod;
}
cout << ans << endl;
return 0;
}