1. 程式人生 > 其它 >牛客練習賽74 E CCA的期望(算概率的技巧+floyd處理)

牛客練習賽74 E CCA的期望(算概率的技巧+floyd處理)

技術標籤:思維數學

牛客地址
題目描述
是否經常有藝術創作的衝動,但卻限於水平無法描繪?那就交給隨機吧!
給定一張 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 second using 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() { ios int T; //cin>>T; T=1; while(T--) { solve(); } return 0; }