CCA的期望(数学期望+Floyd)

题目链接:牛客练习赛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 - (\frac{cnt - y}{cnt})^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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值