[赛记] 多校A层冲刺NOIP2024模拟赛25

图 (a) 100pts

看到提示中有数一个数的二进制下 $ 1 $ 的个数,所以考虑怎么转化这个题,考虑开 $ n $ 个 bitset,第 $ i $ 个 bitset 中如果第 $ j $ 位是 $ 1 $,代表存在边 $ (i, j) $,否则不存在,对于每次修改,直接将 $ S, T $ 两个集合对应的每个点互相异或一下即可;

然后最后统计一下,注意我们只考虑形如 $ (i, j), i < j $ 的边,这样可以避免重复;

时间复杂度:$ \Theta(\frac{n^2 m}{w}) $,正好可以过;

其实这题应该是跑不满,所以较轻松;

点击查看代码
#include <iostream>
#include <cstdio>
#include <bitset>
using namespace std;
int n, m;
bitset<10005> b[10005], s, t;
char a[10005];
long long ans;
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 >> m;
	for (int i = 1; i <= m; i++) {
		cin >> (a + 1);
		s.reset();
		t.reset();
		for (int j = 1; j <= n; j++) {
			if (a[j] == '1') t[j] = 1;
			else if (a[j] == '2') s[j] = 1;
			else if (a[j] == '3') {
				t[j] = 1;
				s[j] = 1;
			}
		}
		for (int j = 1; j <= n; j++) {
			if (a[j] == '1') b[j] ^= s;
			else if (a[j] == '2') b[j] ^= t;
			else if (a[j] == '3') {
				b[j] ^= (s | t);
			}
		}
	}
	for (int i = 1; i <= n; i++) {
		b[i] >>= (i + 1);
		ans += 1ll * b[i].count();
	}
	cout << ans;
	return 0;
}

序列 (b) 0pts

挺人类智慧的,其实转化以后并不难写,但是我被Hack控了一晚上,还把我1e-15的精度给卡了。。。

考虑最后求的是乘积和,所以考虑将所有操作转化成乘积的形式

对于赋值,最多只会赋值一次,是最大的那个,所以我们直接给它转化成加法;

对于加法,发现会从最大的开始加,所以对于一个加操作 $ y $,设所有加操作为 $ x $,那么它对乘积的贡献为 $ \frac{\sum_{i}^{x_i > y} + a_i + y}{\sum_{i}^{x_i > y} + a_i} $;

对于乘法,直接乘即可;

然后我们要处理一种情况:分母在模意义下为 $ 0 $

那么我们发现,这只能对应加法操作,而且前面会出现一个分子为 $ 0 $ 的情况

所以对于这种情况,我们看看前面还有多少个分子为 $ 0 $ 的情况,如果只剩一个,那么我们就把所有分子为 $ 0 $ 的数的分母和分母为 $ 0 $ 的数的分子对应合并起来,然后统计一下答案即可;

时间复杂度: $ \Theta(m \log(mod - 2)) $;

点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;
const long long mod = 1e9 + 7;
int n, m;
long long a[500005], t[500005], x[500005], y[500005], ans[500005], ma[500005], res[500005], pos[500005];
vector<long long> v[500005];
struct sss{
	long double val;
	long long a, b, id;
	bool operator <(const sss &A) const {
		return (__int128)a * A.b > (__int128)A.a * b;
	}
}e[500005];
int cnt;
set<int> s;
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;
}
int main() {
	freopen("b.in", "r", stdin);
	freopen("b.out", "w", stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	for (int i = 1; i <= m; i++) {
		cin >> t[i] >> x[i] >> y[i];
		if (t[i] == 1) ma[x[i]] = max(ma[x[i]], y[i]);
		else if (t[i] == 2) {
			v[x[i]].push_back(y[i]);
		} else {
			e[++cnt] = {1.00 * y[i], y[i], 1, x[i]};
		}
	}
	for (int i = 1; i <= n; i++) {
		if (ma[i] > a[i]) v[i].push_back(ma[i] - a[i]);
		sort(v[i].begin(), v[i].end(), greater<long long>());
		long long sum = 0;
		for (int j = 0; j < v[i].size(); j++) {
			e[++cnt] = {1.00 * (a[i] + sum + v[i][j]) / (a[i] + sum), a[i] + sum + v[i][j], a[i] + sum, i};
			sum += v[i][j];
		}
	}
	sort(e + 1, e + 1 + cnt);
	long long ans = 1;
	for (int i = 1; i <= n; i++) {
		ans = ans * a[i] % mod;
	}
	cout << ans << ' ';
	res[0] = 1;
	for (int i = 1; i <= m; i++) {
		if (i > cnt) {
			for (int j = i; j <= m; j++) {
				cout << ans << ' ';
			}
			return 0;
		}
		res[i] = res[i - 1];
		if (e[i].a % mod != 0 && e[i].b % mod != 0) {
			res[i] = res[i] * ksm(e[i].b % mod, mod - 2) % mod * (e[i].a % mod) % mod;
		}
		if (e[i].a % mod == 0) {
			s.insert(i);
			pos[e[i].id] = i;
		}
		if (e[i].b % mod == 0) {
			e[i].b = e[pos[e[i].id]].b;
			long long p = 1;
			if (s.size() == 1) p = res[*s.begin() - 1];
			ans = p * ksm(e[i].b % mod, mod - 2) % mod * (e[i].a % mod) % mod;
			if (s.size() > 1) {
				cout << 0 << ' ';
				s.erase(prev(s.end()));
				continue;
			}
			for (int j = *s.begin() + 1; j < i; j++) {
				if (!(e[j].a % mod) || !(e[j].b % mod)) continue;
				ans = ans * ksm(e[j].b % mod, mod - 2) % mod * (e[j].a % mod) % mod;
			}
			s.erase(prev(s.end()));
			cout << ans << ' ';
			continue;
		}
		if (i <= cnt) ans = ans * ksm(e[i].b % mod, mod - 2) % mod * (e[i].a % mod) % mod;
		cout << ans << ' ';
	}
	return 0;
}

字符串 (d) 10pts

数据结构题,但是关键是想到数据结构

考虑这个东西怎么统计,不难发现,我们按它给的字符串顺序对这个原序列进行统计,那么我们的答案即为相邻两个数 $ i, j, i \leq j $ 的个数 $ + 1 $;

对于这个东西,我们发现 $ k \leq 10 $,所以我们可以暴力 $ \Theta(k^2) $ 统计所有相邻的对数出现的个数并放在线段树上,修改直接 $ \Theta(k^2 \log n) $ 暴修,查询直接查询所有 $ \Theta(k^2) $ 个对的出现次数和;

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

主要是不要想偏,并不难实现;

点击查看代码
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
int n, m, k;
char s[500005], c[28];
int su[11][11], ans;
vector<int> v, a;
namespace SEG{
	inline int ls(int x) {
		return x << 1;
	}
	inline int rs(int x) {
		return x << 1 | 1;
	}
	struct sss{
		int l, r, sum[11][11], lval, rval, lz;
	}tr[800005];
	inline void w(int id, int x) {
		tr[id].lz += x; tr[id].lz %= k;
		tr[id].lval += x; tr[id].rval += x; tr[id].lval %= k; tr[id].rval %= k;
		for (int i = 0; i < k; i++) {
			for (int j = 0; j < k; j++) {
				su[i][j] = tr[id].sum[i][j];
				tr[id].sum[i][j] = 0;
			}
		}
		for (int i = 0; i < k; i++) {
			for (int j = 0; j < k; j++) {
				tr[id].sum[(i + x) % k][(j + x) % k] += su[i][j];
			}
		}
	}
	inline void push_up(int id) {
		for (int i = 0; i < k; i++) {
			for (int j = 0; j < k; j++) {
				tr[id].sum[i][j] = tr[ls(id)].sum[i][j] + tr[rs(id)].sum[i][j];
			}
		}
		tr[id].lval = tr[ls(id)].lval;
		tr[id].rval = tr[rs(id)].rval;
		tr[id].sum[tr[ls(id)].rval][tr[rs(id)].lval]++;
	}
	inline void push_down(int id) {
		if (tr[id].lz) {
			w(ls(id), tr[id].lz);
			w(rs(id), 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].lval = tr[id].rval = (s[l] - 'a');
			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 x) {
		if (tr[id].l >= l && tr[id].r <= r) {
			w(id, x);
			return;
		}
		push_down(id);
		int mid = (tr[id].l + tr[id].r) >> 1;
		if (l <= mid) add(ls(id), l, r, x);
		if (r > mid) add(rs(id), l, r, x);
		push_up(id);
	}
	void ask(int id, int l, int r) {
		if (tr[id].l == l && tr[id].r == r) {
			a.push_back(id);
			for (int i = v.size() - 1; i >= 0; i--) {
				for (int j = i; j >= 0; j--) {
					ans += tr[id].sum[v[i]][v[j]];
				}
			}
			return;
		}
		push_down(id);
		int mid = (tr[id].l + tr[id].r) >> 1;
		if (r <= mid) ask(ls(id), l, r);
		else if (l > mid) ask(rs(id), l, r);
		else {
			ask(ls(id), l, mid);
			ask(rs(id), mid + 1, r);
		}
	}
}
int main() {
	freopen("d.in", "r", stdin);
	freopen("d.out", "w", stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> m >> k;
	cin >> (s + 1);
	SEG::bt(1, 1, n);
	int o, l, r, x;
	for (int i = 1; i <= m; i++) {
		cin >> o >> l >> r;
		if (o == 1) {
			cin >> x;
			SEG::add(1, l, r, x);
		}
		if (o == 2) {
			cin >> (c + 1);
			v.clear();
			a.clear();
			for (int j = 1; j <= k; j++) {
				v.push_back((c[j] - 'a'));
			}
			ans = 0;
			SEG::ask(1, l, r);
			for (int y = 1; y < a.size(); y++) {
				for (int j = v.size() - 1; j >= 0; j--) {
					for (int z = j; z >= 0; z--) {
						if (v[j] == SEG::tr[a[y - 1]].rval && v[z] == SEG::tr[a[y]].lval) {
							ans++;
							break;
						}
					}
				}
			}
			cout << ans + 1 << '\n';
		}
	}
	return 0;
}
posted @ 2024-11-23 21:39  Peppa_Even_Pig  阅读(16)  评论(0编辑  收藏  举报