【LOJ2263】「CTSC2017」游戏

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/83624929

【题目链接】

【思路要点】

  • 仿照题目的第二问的解法,我们先来考虑本题的平方做法。
  • B B 表示事件 x i = 1 x_i=1 A A 表示事件 x j = c x_j=c ,其中 j j i i 之前第一个确定的事件,若 i i 之前没有确定的事件,则 j = 0 j=0 C C 表示事件 x k = c x_k=c ,其中 k k i i 之后第一个确定的事件,若 i i 之后没有确定的事件,则 k = N + 1 k=N+1
  • 我们希望计算概率 P ( B A , C ) P(B|A,C) ,根据贝叶斯公式:
    P ( B A , C ) = P ( A , C B ) P ( B ) P ( A , C ) = P ( A B ) P ( C B ) P ( B ) P ( C A ) P ( A ) = P ( B A ) P ( C B ) P ( C A ) P(B|A,C)=\frac{P(A,C|B)*P(B)}{P(A,C)}=\frac{P(A|B)*P(C|B)*P(B)}{P(C|A)*P(A)}=\frac{P(B|A)*P(C|B)}{P(C|A)}
  • 区间 [ j , k ) [j,k) 的贡献即为 i = j k 1 P ( B A , C ) = i = j k 1 P ( B A ) P ( C B ) P ( C A ) \sum_{i=j}^{k-1}P(B|A,C)=\frac{\sum_{i=j}^{k-1}P(B|A)*P(C|B)}{P(C|A)} ,该式可以看做从事件 A A 转移到事件 C C 的每一条路径中,每经过一次 x i = 1 x_i=1 就使计数器 c n t cnt 1 1 ,最后到达 C C c n t cnt 值的期望,可以用线段树维护矩阵做到 O ( L o g N ) O(LogN) 查询。
  • 每次单点插入/删除时在 s e t set 中找前驱后继,更新答案即可。
  • 时间复杂度 O ( N L o g N ) O(NLogN)

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
int n, m; char type;
double p[MAXN], q[MAXN], t[MAXN][2][2];
struct info {double p[2][2], e[2][2]; };
//0 : lose, 1 : win
info cipher() {
	info ans;
	memset(ans.p, 0, sizeof(ans.p));
	memset(ans.e, 0, sizeof(ans.e));
	return ans;
}
info unit() {
	info ans = cipher();
	ans.p[0][0] = ans.p[1][1] = ans.e[1][1] = 1;
	return ans;
}
info merge(info a, info b, int pos) {
	info ans = cipher();
	for (int i = 0; i <= 1; i++)
	for (int j = 0; j <= 1; j++) {
		for (int k = 0; k <= 1; k++)
		for (int l = 0; l <= 1; l++) {
			ans.p[i][j] += a.p[i][k] * t[pos][k][l] * b.p[l][j];
			ans.e[i][j] += (a.p[i][k] * t[pos][k][l] * b.p[l][j]) * (a.e[i][k] + b.e[l][j]);
		}
		ans.e[i][j] /= ans.p[i][j];
	}
	return ans;
}
struct SegmentTree {
	struct Node {
		int lc, rc;
		info ans;
	} a[MAXN * 2];
	int n, size, root;
	void update(int root, int l, int r) {
		int mid = (l + r) / 2;
		a[root].ans = merge(a[a[root].lc].ans, a[a[root].rc].ans, mid + 1);
	}
	void build(int &root, int l, int r) {
		root = ++size;
		if (l == r) {
			a[root].ans = unit();
			return;
		}
		int mid = (l + r) / 2;
		build(a[root].lc, l, mid);
		build(a[root].rc, mid + 1, r);
		update(root, l, r);
	}
	void init(int x) {
		n = x;
		root = size = 0;
		build(root, 0, n);
	}
	info query(int root, int l, int r, int ql, int qr) {
		if (l == ql && r == qr) return a[root].ans;
		int mid = (l + r) / 2;
		if (mid >= qr) return query(a[root].lc, l, mid, ql, qr);
		else if (mid + 1 <= ql) return query(a[root].rc, mid + 1, r, ql, qr);
		else return merge(query(a[root].lc, l, mid, ql, mid), query(a[root].rc, mid + 1, r, mid + 1, qr), mid + 1);
	}
	info query(int l, int r) {
		return query(root, 0, n, l, r);
	}
	double getans(pair <int, int> x, pair <int, int> y) {
		info tmp = query(x.first, y.first);
		return tmp.e[x.second][y.second] - y.second;
	}
} ST;
set <pair <int, int> > st;
int main() {
	scanf("%d%d %c", &n, &m, &type);
	for (int i = 1; i <= n; i++) {
		scanf("%lf", &p[i]);
		if (i == 1) q[i] = p[i];
		else scanf("%lf", &q[i]);
		t[i][0][0] = 1 - q[i];
		t[i][0][1] = q[i];
		t[i][1][0] = 1 - p[i];
		t[i][1][1] = p[i];
	}
	t[n + 1][0][0] = t[n + 1][1][0] = 1;
	ST.init(n + 1);
	st.insert(make_pair(0, 0));
	st.insert(make_pair(n + 1, 0));
	double now = ST.getans(make_pair(0, 0), make_pair(n + 1, 0));
	cerr << now << endl;
	for (int i = 1; i <= m; i++) {
		char opt[15]; int x;
		scanf("\n%s%d", opt, &x);
		if (opt[0] == 'a') {
			int y; read(y);
			pair <int, int> tmp = make_pair(x, y);
			auto suf = st.lower_bound(tmp), pre = suf; pre--;
			now -= ST.getans(*pre, *suf);
			now += ST.getans(*pre, tmp);
			now += ST.getans(tmp, *suf);
			st.insert(tmp);
		} else {
			pair <int, int> tmp = make_pair(x, 0);
			auto pos = st.lower_bound(tmp), pre = pos, suf = pos; suf++, pre--;
			now += ST.getans(*pre, *suf);
			now -= ST.getans(*pre, *pos);
			now -= ST.getans(*pos, *suf);
			st.erase(pos);
		}
		printf("%.10lf\n", now);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39972971/article/details/83624929