[赛记] csp-s模拟10

欧几里得的噩梦 -pts

看见是个线性基的题就没打;

其实也不是线性基,只不过模拟了一下它的过程;

考虑插入一位数时它能不能被表示,其实就是它异或上线性基中的某些值后可不可以为 $ 0 $,那么我们就可以将插入的单独一位数与 $ 0 $ 连边,将两位数互相连边,这样每插入一位数时看看它与 $ 0 $ 连不连通即可,这个可以用并查集实现;

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

点击查看代码
#include <iostream>
#include <cstdio>
using namespace std;
#define int long long
const int mod = 1e9 + 7;
int n, m;
int fa[500005];
int find(int x) {
	if (x != fa[x]) fa[x] = find(fa[x]);
	return fa[x];
}
int rem[500005];
int ksm(int a, int b) {
	int ans = 1;
	while(b) {
		if (b & 1) ans = ans * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return ans;
}
namespace LB{
	void add(int id, int x, int y) {
		x = find(x);
		y = find(y);
		if (x == y) return;
		if (x < y) swap(x, y);
		if (x != 0 || y != 0) {
			fa[x] = y;
			rem[++rem[0]] = id;
		}
	}
}
using namespace LB;
signed main() {
	freopen("Euclid.in", "r", stdin);
	freopen("Euclid.out", "w", stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= m; i++) fa[i] = i;
	int s;
	int x, y;
	for (int i = 1; i <= n; i++) {
		cin >> s;
		if (s == 1) {
			cin >> x;
			add(i, x, 0);
		}
		if (s == 2) {
			cin >> x >> y;
			if (x < y) swap(x, y);
			add(i, x, y);
		}
	}
	cout << ksm(2, rem[0]) << ' ' << rem[0] << '\n';
	for (int i = 1; i <= rem[0]; i++) cout << rem[i] << ' ';
	return 0;
}

购物 0pts

赛时没打;

引用题解:这种题先想单个k怎么判断,找充要条件。

考虑对于一个数 $ x $ ,它的合法的 $ k $ 值范围为 $ [\lceil \frac x2 \rceil, x] $,所以我们可以找出所有数,求所有的区间的并即可;

找出所有的数复杂度是指数级的,是不行的;

所以考虑单个 $ k $,发现如果原序列存在 $ [k, 2k] $ 的数,那么这个 $ k $ 合法,否则找所有小于 $ k $ 的数之和,如果这个和大于等于 $ k $ 也合法(因为这样就保证了有落在 $ [k, 2k] $ 中的和),所以我们只需维护一个前缀和,然后将所有 $ n $ 个数和 $ n - 1 $ 个前缀和所构成的 $ [\lceil \frac x2 \rceil, x] $ 的区间求并即可;

对于区间求并,可以珂朵莉树维护(其实就是一个 set);

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

点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <set>
using namespace std;
int n;
long long a[500005];
long long ans;
long long w(long long a, long long b) {
	if (a % b == 0) return a / b;
	else return a / b + 1;
}
struct sss{
	mutable long long l, r;
	bool operator <(const sss &A) const {
		return l < A.l;
	}
};
set<sss> s;
void add(long long l, long long r) {
	if (s.empty()) {
		s.insert({l, r});
		return;
	}
	set<sss>::iterator it = s.lower_bound({l, 0});
	if (it == s.end()) {
		it--;
		if (it -> r < l) {
			s.insert({l, r});
			return;
		}
	}
	if (it -> l > l) it--;
	it -> l = min(it -> l, l);
	it -> r = max(it -> r, r);
	it++;
	for (set<sss>::iterator i = it; i != s.end(); i++) {
		if (i -> l > r) break;
		if (i -> r <= r) s.erase(i);
		else {
			i -> l = r + 1;
			break;
		}
	}
}
int main() {
	freopen("buy.in", "r", stdin);
	freopen("buy.out", "w", stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	sort(a + 1, a + 1 + n);
	for (int i = 1; i <= n; i++) {
		long long l = w(a[i], 2);
		add(l, a[i]);
	}
	long long sum = a[1];
	for (int i = 2; i <= n; i++) {
		sum += a[i];
		long long l = w(sum, 2);
		add(l, sum);
	}
	for (set<sss>::iterator it = s.begin(); it != s.end(); it++) {
		ans += (it -> r - it -> l + 1);
	}
	cout << ans;
	return 0;
}

ants 50pts

就这道题拿分了。。。

赛时用的线段树维护莫队,时间复杂度 $ \Theta(n \sqrt n \log n) \ TLE $ 了;

正解:回滚莫队;

其实这题主要的时间开销在删除上,所以考虑用只加不减的回滚莫队;

每次用并查集维护一下最长值域联通段,然后撤销一下即可;

赛时把回滚莫队复杂度记成 $ \Theta(n^{\frac53}) $ 导致没打,其实这是带修莫队的时间复杂度

时间复杂度: $ \Theta(n \sqrt n \log n) $,但是并查集常数小,所以能过;

好像还有 $ \Theta(1) $ 链表维护的做法,没写;

点击查看代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <stack>
#include <vector>
using namespace std;
int n, m;
int a[100005];
int st[505], ed[505], belog[100005];
int sq;
struct sss{
	int l, r, id;
	inline bool operator <(const sss &A) const {
		if (belog[l] != belog[A.l]) {
			return l < A.l;
		} else {
			return r < A.r;
		}
	}
}e[100005];
int fa[100005], siz[100005], ans[100005];
int find(int x) {
	if (x != fa[x]) fa[x] = find(fa[x]);
	return fa[x];
}
stack<pair<pair<bool, int>, pair<int, int> > > s;
vector<int> v;
bool vis[100005];
int ma, lans;
void add(int o, int x) {
	vis[x] = true;
	if (o == 1) s.push({{1, x}, {fa[find(x)], siz[find(x)]}});
	if (!vis[x - 1] && !vis[x + 1]) return;
	if (vis[x - 1]) {
		if (o == 1) s.push({{0, find(x - 1)}, {fa[find(x - 1)], siz[find(x - 1)]}});
		siz[find(x - 1)] += siz[find(x)];
		siz[find(x)] = 1;
		fa[find(x)] = find(x - 1);
		ma = max(ma, siz[find(x - 1)]);
	}
	if (vis[x + 1]) {
		if (o == 1) s.push({{0, find(x + 1)}, {fa[find(x + 1)], siz[find(x + 1)]}});
		siz[find(x)] += siz[find(x + 1)];
		siz[find(x + 1)] = 1;
		fa[find(x + 1)] = find(x);
		ma = max(ma, siz[find(x)]);
	}
}
int main() {
	freopen("ants.in", "r", stdin);
	freopen("ants.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 >> e[i].l >> e[i].r;
		e[i].id = i;
	}
	sq = sqrt(n);
	for (int i = 1; i <= sq; i++) {
		st[i] = (i - 1) * sq + 1;
		ed[i] = i * sq;
	}
	ed[sq] = n;
	for (int i = 1; i <= sq; i++) {
		for (int j = st[i]; j <= ed[i]; j++) {
			belog[j] = i;
		}
	}
	for (int i = 1; i <= n; i++) {
		fa[i] = i;
		siz[i] = 1;
	}
	sort(e + 1, e + 1 + m);
	int l = 1;
	int r = 0;
	int ls = 0;
	for (int i = 1; i <= m; i++) {
		ma = 1;
		if (belog[e[i].l] == belog[e[i].r]) {
			v.clear();
			for (int j = e[i].l; j <= e[i].r; j++) {
				v.push_back(a[j]);
			}
			v.push_back(0x3f3f3f3f);
			sort(v.begin(), v.end());
			int an = 0, sum = 1;
			for (int j = 0; j < v.size(); j++) {
				if (v[j + 1] != v[j] + 1) {
					an = max(an, sum);
					sum = 1;
				} else {
					sum++;
				}
			}
			ans[e[i].id] = an;
			continue;
		}
		if (belog[e[i].l] != ls) {
			lans = 1;
			ls = belog[e[i].l];
			while(!s.empty()) s.pop();
			for (int j = 1; j <= n; j++) {
				fa[j] = j;
				siz[j] = 1;
				vis[j] = false;
			}
			l = ed[belog[e[i].l]];
			r = ed[belog[e[i].l]] - 1;
		}
		if (l < ed[belog[e[i].l]]) {
			while(!s.empty()) {
				pair<pair<bool, int> , pair<int, int> > p = s.top();
				s.pop();
				if (p.first.first) vis[p.first.second] = false;
				fa[p.first.second] = p.second.first;
				siz[p.first.second] = p.second.second;
			}
			l = ed[belog[e[i].l]];
		}
		while(r < e[i].r) add(0, a[++r]);
		lans = max(ma, lans);
		while(l > e[i].l) add(1, a[--l]);
		ans[e[i].id] = max(lans, ma);
	}
	for (int i = 1; i <= m; i++) {
		cout << ans[i] << '\n';
	}
	return 0;
}
posted @ 2024-10-10 16:23  Peppa_Even_Pig  阅读(10)  评论(0编辑  收藏  举报