Live2D

Solution -「CTSC 2017」「洛谷 P3772」游戏

Description

  有 n 个随机真值 x1..n, 已知 P(x1=1)=p1, 对于 2in, P(xi=1xi1=1)=pi, P(xi=1xi1=0)=qi. 设事件集合 S, 初始时 S=. 给出 m 次修改, 每次修改:

  1. 给定 i,c, 令 SS{xi=c}.
  2. 给定 i, 令 SS{xi=}.

每次修改完成后, 求出 E(i=1nxiS), 保留浮点.

Solution

  令 ξ:{x1..n}i=1nxi, 那么

E(ξS)=iiP(ξ=iS)=iiP(ξ=iS)/P(S)=E([S]×ξ)/P(S),

其中当 S 内事件全部发生时 [S]=1, 否则 [S]=0.

  现在, 我们的任务变成了维护出 E([S]×ξ)P(S). 容易发现从 i1 的信息推到 i 的信息是一个线性变换, 我们需要的东西大概有: P(xi=1S), P(xi=0S), E([Sxi=1]×ξi)E([Sxi=0]×ξi), 其中 ξi:{x1..i}j=1ixj, 然后按照规则变换一下:

[P(xi=1S)P(xi=0S)E([Sxi=1]ξi)E([Sxi=0]ξi)]=[piqi1pi1qipiqipiqi1pi1qi][P(xi1=1S)P(xi1=0S)E([Sxi1=1]ξi1)E([Sxi1=0]ξi1)].

中间的转移矩阵是 {xi=}S 的情况; 当 {xi=1/0}S 时, 只需要对应保留矩阵中红色行和蓝色行即可, 其组合意义也比较简单.

  最后, 钦定 x0=1, 将 [1000]T 输入线性变换, 就能得到最终答案. 线段树维护矩阵, 复杂度 43×O(nlogn). 常数好像 ... 有点大欸.

Code

/*+Rainybunny+*/

#include <bits/stdc++.h>

#define rep(i, l, r) for (int i = l, rep##i = r; i <= rep##i; ++i)
#define per(i, r, l) for (int i = r, per##i = l; i >= per##i; --i)

#define double long double

const int MAXN = 2e5;
int n, m;
double p[MAXN + 5], q[MAXN + 5];

struct Matrix {
    double mat[4][4];
    // Matrix(): mat{} {}
    inline double* operator [] (const int k) { return mat[k]; }
    inline Matrix operator * (const Matrix& u) const {
        Matrix ret; memset(ret.mat, 0, sizeof ret.mat);
        rep (i, 0, 3) rep (k, 0, 3) rep (j, 0, 3) {
            ret[i][j] += mat[i][k] * u.mat[k][j];
        }
        return ret;
    }
};

#define unknown(i) Matrix{{ \
    { p[i], q[i] }, \
    { 1 - p[i], 1 - q[i] }, \
    { p[i], q[i], p[i], q[i] }, \
    { 0, 0, 1 - p[i], 1 - q[i] } \
}}

#define winR(i) Matrix{{ \
    { p[i], q[i] }, \
    {}, \
    { p[i], q[i], p[i], q[i] }, \
    {} \
}}

#define winB(i) Matrix{{ \
    {}, \
    { 1 - p[i], 1 - q[i] }, \
    {}, \
    { 0, 0, 1 - p[i], 1 - q[i] } \
}}

struct SegmentTree {
    Matrix uni[MAXN << 2];

    inline void pushup(const int u) {
        uni[u] = uni[u << 1 | 1] * uni[u << 1];
    }

    inline void build(const int u, const int l, const int r) {
        if (l == r) return void(uni[u] = unknown(l));
        int mid = l + r >> 1;
        build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
        pushup(u);
    }

    inline void modify(const int u, const int l, const int r,
      const int x, const Matrix k) {
        if (l == r) return void(uni[u] = k);
        int mid = l + r >> 1;
        if (x <= mid) modify(u << 1, l, mid, x, k);
        else modify(u << 1 | 1, mid + 1, r, x, k);
        pushup(u);
    }
} sgt;

int main() {
    scanf("%d %d %*s %Lf", &n, &m, &p[1]);
    rep (i, 2, n) scanf("%Lf %Lf", &p[i], &q[i]);
    
    sgt.build(1, 1, n);

    while (m--) {
        char op[10]; int i, c;
        scanf("%s", op);
        if (op[0] == 'a') {
            scanf("%d %d", &i, &c);
            sgt.modify(1, 1, n, i, c ? winR(i) : winB(i));
        } else {
            scanf("%d", &i);
            sgt.modify(1, 1, n, i, unknown(i));
        }
        auto& ans = sgt.uni[1];
        printf("%.12Lf\n", (ans[2][0] + ans[3][0]) / (ans[0][0] + ans[1][0]));
    }
    return 0;
}

posted @   Rainybunny  阅读(49)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示