[赛记] 冲刺CSP联训模拟2

三道计数 + 一道数据结构也是没谁了

这场可是好好锻炼了我的写暴搜能力。。。

挤压 20pts

暴搜20pts;

把最后的答案进行二进制拆解,即 $ ans = 2^i + 2^j + 2^k + ... $,那么答案的平方为 $ \sum_{i = 0}^{30} \sum_{j = 0}^{30} s_i s_j 2^{i + j} $,其中 $ s_i, s_j $ 代表答案二进制拆解后这一位是 $ 1 $ 还是 $ 0 $;

那么我们发现,答案的平方只和答案二进制拆解后的任意两位有关,所以我们直接设 $ f_{k, i, j, 0/1, 0/1} $ 表示考虑到第 $ k $ 个数字,第 $ i $ 位是 $ 0/1 $,第 $ j $ 位是 $ 0/1 $ 的概率即可;

这其实是个概率 $ DP $,从第一步开始其实比较难想

点击查看代码
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const long long mod = 1e9 + 7;
long long n;
long long a[500005], q[500005];
long long ksm(long long a, long long b) {
	long long ans = 1;
	while(b) {
		if (b & 1) ans = ans * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return ans;
}
long long f[35][35][2][2], now[2][2];
int main() {
	freopen("a.in", "r", stdin);
	freopen("a.out", "w", stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n;
	long long kk = ksm(1000000000, mod - 2);
	for (int i = 1; i <= n; i++) cin >> a[i];
	for (int i = 1; i <= n; i++) {
		cin >> q[i];
		q[i] = q[i] * kk % mod;
	}
	for (int i = 0; i <= 30; i++) {
		for (int j = 0; j <= 30; j++) {
			f[i][j][0][0] = 1;
		}
	}
	for (int i = 1; i <= n; i++) {
		for (int j = 0; j <= 30; j++) {
			for (int k = 0; k <= 30; k++) {
				for (int l = 0; l <= 1; l++) {
					for (int r = 0; r <= 1; r++) {
						now[l][r] = f[j][k][l][r];
					}
				}
				bool tj = false;
				bool tk = false;
				if ((a[i] >> j) & 1) tj = true;
				if ((a[i] >> k) & 1) tk = true;
				for (int l = 0; l <= 1; l++) {
					for (int r = 0; r <= 1; r++) {
						f[j][k][l][r] = (now[l][r] * (1 - q[i] + mod) % mod + now[l ^ tj][r ^ tk] * q[i] % mod) % mod;
					}
				}
			}
		}
	}
	long long ans = 0;
	for (int i = 0; i <= 30; i++) {
		for (int j = 0; j <= 30; j++) {
			ans = (ans + f[i][j][1][1] * ksm(2, i + j) % mod) % mod;
		}
	}
	cout << ans;
	return 0;
}

工地难题 30pts

暴搜30pts

考虑正解,是个容斥,题解详见[算法] 容斥的例题;

星空遗迹 20pts

$ \Theta(n^3) $ 暴力20pts;

考虑正解,发现可以单调栈维护,满足下面的能够赢上面的,答案就是栈大小最小时对应的元素,于是可以线段树区间修改区间查最小;

时间复杂度:$ \Theta(n \log n) $;

点击查看代码
#include <iostream>
#include <cstdio>
using namespace std;
int n, q;
char s[500005];
char win(char x, char y) {
	if (x == y) return x;
	if ((x == 'R' && y == 'S') || (x == 'S' && y == 'R')) return 'R';
	if ((x == 'S' && y == 'P') || (x == 'P' && y == 'S')) return 'S';
	if ((x == 'P' && y == 'R') || (x == 'R' && y == 'P')) return 'P';
}
int f[500005];
namespace SEG{
	inline int ls(int x) {
		return x << 1;
	}
	inline int rs(int x) {
		return x << 1 | 1;
	}
	struct sss{
		int l, r, lz;
		pair<int, int> mi;
	}tr[3000005];
	inline void push_up(int id) {
		tr[id].mi = min(tr[ls(id)].mi, tr[rs(id)].mi);
	}
	inline void push_down(int id) {
		if (tr[id].lz) {
			tr[ls(id)].lz += tr[id].lz;
			tr[rs(id)].lz += tr[id].lz;
			tr[ls(id)].mi.first += tr[id].lz;
			tr[rs(id)].mi.first += tr[id].lz;
			tr[id].lz = 0;
		}
	}
	void bt(int id, int l, int r) {
		tr[id].l = l;
		tr[id].r = r;
		if (l == r) {
			tr[id].mi = {f[l], l};
			return;
		}
		int mid = (l + r) >> 1;
		bt(ls(id), l, mid);
		bt(rs(id), mid + 1, r);
		push_up(id);
	}
	void add(int id, int l, int r, int d) {
		if (tr[id].l >= l && tr[id].r <= r) {
			tr[id].mi.first += d;
			tr[id].lz += d;
			return;
		}
		push_down(id);
		int mid = (tr[id].l + tr[id].r) >> 1;
		if (l <= mid) add(ls(id), l, r, d);
		if (r > mid) add(rs(id), l, r, d);
		push_up(id);
	}
	pair<int, int> ask(int id, int l, int r) {
		if (tr[id].l >= l && tr[id].r <= r) {
			return tr[id].mi;
		}
		push_down(id);
		int mid = (tr[id].l + tr[id].r) >> 1;
		if (r <= mid) return ask(ls(id), l, r);
		else if (l > mid) return ask(rs(id), l, r);
		else return min(ask(ls(id), l, mid), ask(rs(id), mid + 1, r));
	}
}
using namespace SEG;
int main() {
	freopen("a.in", "r", stdin);
	freopen("a.out", "w", stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> q;
	for (int i = 1; i <= n; i++) {
		cin >> s[i];
	}
	f[1] = 1;
	for (int i = 2; i <= n; i++) {
		if (s[i] == s[i - 1]) {
			f[i] = f[i - 1];
			continue;
		}
		if (win(s[i], s[i - 1]) == s[i]) {
			f[i] = f[i - 1] - 1;
			continue;
		}
		if (win(s[i], s[i - 1]) == s[i - 1]) {
			f[i] = f[i - 1] + 1;
			continue;
		}
	}
	bt(1, 1, n);
	int ss, l, r;
	char y;
	for (int i = 1; i <= q; i++) {
		cin >> ss >> l;
		if (ss == 1) {
			cin >> y;
			if (y == s[l]) continue;
			if (l > 1) {
				int ls = 0;
				if (s[l - 1] == s[l]) ls = 0;
				else if (win(s[l - 1], s[l]) == s[l - 1]) ls = 1;
				else if (win(s[l - 1], s[l]) == s[l]) ls = -1;
				int now = 0;
				if (s[l - 1] == y) now = 0;
				else if (win(s[l - 1], y) == s[l - 1]) now = 1;
				else if (win(s[l - 1], y) == y) now = -1;
				add(1, l, n, now - ls);
			}
			if (l < n) {
				int ls = 0;
				if (s[l + 1] == s[l]) ls = 0;
				else if (win(s[l], s[l + 1]) == s[l]) ls = 1;
				else if (win(s[l], s[l + 1]) == s[l + 1]) ls = -1;
				int now = 0;
				if (y == s[l + 1]) now = 0;
				else if (win(s[l + 1], y) == y) now = 1;
				else if (win(s[l + 1], y) == s[l + 1]) now = -1;
				add(1, l + 1, n, now - ls); 
			}
			s[l] = y;
		}
		if (ss == 2) {
			cin >> r;
			cout << s[ask(1, l, r).second] << '\n';
		}
	}
	return 0;
}
posted @ 2024-10-05 15:05  Peppa_Even_Pig  阅读(8)  评论(0编辑  收藏  举报