牛客地址
题目描述
是否经常有艺术创作的冲动,但却限于水平无法描绘?那就交给随机吧!
给定一张 n 个点 m 条边的无向带边权连通图,点有颜色,为黑或白,保证无自环和重边。
定义一次操作为:随机选择两个不同的点,将它们之间的最短路上的点全部染黑(若有多条最短路就都染黑)。
现在你想知道,经过 k 次操作后,黑色点的期望个数是多少 。
思路:算这个的期望,我们可以转化为每个点对期望的贡献,既算出每个点变成黑色的概率。
任意选择两个不同的点,那么就有总数 cnt=n*(n-1)/2;
假设经过i点的最短数次数为y(这个可以由floyd算法算出);
如果该点的颜色本来就为黑色,那么期望贡献为1;
否则,选择k次,至少一次选择的路径含有该点的期望就为(1-(1-y/cnt)^k)(连续k次都没有选择到 反向思考)
取模除法要使用逆元!
细节看代码:
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstdlib>
#include <stack>
#include <vector>
#include <set>
#include <map>
#include <bitset>
#define INF 0x3f3f3f3f3f3f3f3f
#define inf 0x3f3f3f3f
#define FILL(a,b) (memset(a,b,sizeof(a)))
#define re register
#define lson rt<<1
#define rson rt<<1|1
#define lowbit(a) ((a)&-(a))
#define ios std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
#define fi first
#define rep(i,n) for(int i=0;(i)<(n);i++)
#define rep1(i,n) for(int i=1;(i)<=(n);i++)
#define se secondusing namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,ll> pii;
const ll mod=1023694381;
const ll N =3e6+10;
const double eps = 1e-6;
const double pi=acos(-1);
ll gcd(ll a,ll b){return !b?a:gcd(b,a%b);}
int dx[8]= {1,0,-1,0,1,1,-1,-1}, dy[8] = {0,1,0,-1,1,-1,1,-1};
int n,m,k;
ll dis[1000][1000];
int c[1000];
int sum[1000];
ll pow1(ll a,ll b){ll ans=1;while(b){if(b&1) ans=(ans*a)%mod;a=(a*a)%mod;b/=2;}return ans;
}
void floyd()
{for(int k=1;k<=n;k++){for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){dis[i][j]=min(dis[i][k]+dis[k][j],dis[i][j]);}}}
}
void solve()
{cin>>n>>m>>k;for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){if(i==j) dis[i][j]=0;else dis[i][j]=(ll)1e15;}}for(int i=1;i<=n;i++) cin>>c[i];for(int i=1;i<=m;i++){ll u,v,w;cin>>u>>v>>w;dis[u][v]=w;dis[v][u]=w;}floyd();for(int i=1;i<=n;i++){for(int j=i+1;j<=n;j++){for(int k=1;k<=n;k++){if(dis[i][j]==dis[i][k]+dis[k][j]) sum[k]++;}}}ll cnt=((n-1)*n)/2;ll inv=pow1(pow1(cnt,k),mod-2)%mod;ll ans=0;for(int i=1;i<=n;i++){if(c[i]==1) ans=(ans+1)%mod;else{ans=(ans+((1-(pow1(cnt-sum[i],k)*inv)%mod+mod)%mod))%mod;}}cout<<ans<<endl;
}
int main()
{iosint T;//cin>>T;T=1;while(T--){solve();}return 0;
}