[赛记] 多校A层冲刺NOIP2024模拟赛01【衡中】

构造字符串 50pts

错解50pts;

考虑正解,对于题目中的要求,我们可以转换成若干个相等与不等的操作,若相等则用并查集合并一下,不等则连边,若同块连边则无解,否则从前往后遍历赋值,每次找所连边其它块值的 $ \operatorname{mex} $ 即可;

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

点击查看代码
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
int n, m;
int fa[5005];
int find(int x) {
	if (x != fa[x]) fa[x] = find(fa[x]);
	return fa[x];
}
struct sss{
	int x, y, z;
}e[5005];
int cnt;
vector<int> v[5005];
int ans[5005];
bool vis[5005];
int main() {
	freopen("str.in", "r", stdin);
	freopen("str.out", "w", stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> m;
	for (int i = 1; i <= n; i++) fa[i] = i;
	int cnt = m;
	memset(ans, -1, sizeof(ans));
	for (int i = 1; i <= m; i++) {
		cin >> e[i].x >> e[i].y >> e[i].z;
		if (e[i].x > e[i].y) swap(e[i].x, e[i].y);
		if (e[i].z != 0) {
			int l = e[i].x;
			int r = e[i].y;
			int o = e[i].z;
			while(o) {
				fa[find(l)] = find(r);
				l++;
				r++;
				o--;
			}
			if (r <= n) {
				e[++cnt] = {l, r, 0};
			}
		} else {
			e[++cnt] = e[i];
		}
	}
	for (int i = m + 1; i <= cnt; i++) {
		int l = e[i].x;
		int r = e[i].y;
		if (find(l) == find(r)) {
			cout << -1;
			return 0;
		}
		v[find(l)].push_back(find(r));
		v[find(r)].push_back(find(l));
	}
	for (int i = 1; i <= n; i++) {
		int x = find(i);
		if (ans[x] != -1) continue;
		for (int j = 0; j <= n; j++) vis[j] = false;
		for (int j = 0; j < v[x].size(); j++) {
			if (ans[v[x][j]] != -1) vis[ans[v[x][j]]] = true;
		}
		for (int j = 0; j <= n; j++) {
			if (!vis[j]) {
				ans[x] = j;
				break;
			}
		}
	}
	for (int i = 1; i <= n; i++) {
		cout << ans[find(i)] << ' ';
	}
	return 0;
}

寻宝 100pts

T2放纯搜,也是没谁了;

首先跑一边 $ BFS $ 将连通块缩点,然后在传送门所连接的两个连通块中连单向边,最后从每个人出发点所处连通块 $ BFS $,看看能不能到达终点所处连通块;

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

注意本题并没有具体地给出 $ n, m $ 的范围,所以要给每个点标号,而且输入图的时候要用 vector

点击查看代码
#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
using namespace std;
int n, m, k, q;
vector<char> s[500005];
char c;
bool vis[500005], vi[500005];
int rem[500005];
int belog[500005], sum;
int id(int x, int y) {
	return (x - 1) * m + y;
}
bool in(int x, int y) {
	return x >= 1 && x <= n && y >= 1 && y <= m;
}
int a[5] = {-1, 0, 0, 1};
int b[5] = {0, 1, -1, 0};
void bfs(int x, int y, int now) {
	queue<pair<int, int> > q;
	while(!q.empty()) q.pop();
	q.push({x, y});
	belog[id(x, y)] = now;
	vis[id(x, y)] = true;
	while(!q.empty()) {
		int xx = q.front().first;
		int yy = q.front().second;
		q.pop();
		for (int i = 0; i <= 3; i++) {
			int nx = xx + a[i];
			int ny = yy + b[i];
			if (in(nx, ny) && s[nx][ny] != '#' && !vis[id(nx, ny)]) {
				vis[id(nx, ny)] = true;
				belog[id(nx, ny)] = now;
				q.push({nx, ny});
			}
		}
	}
}
struct sss{
	int t, ne;
}e[500005];
int h[500005], cnt;
void add(int u, int v) {
	e[++cnt].t = v;
	e[cnt].ne = h[u];
	h[u] = cnt;
}
bool afs(int s, int t) {
	if (s == t) return true;
	rem[0] = 0;
	queue<int> q;
	while(!q.empty()) q.pop();
	q.push(s);
	vi[s] = true;
	rem[++rem[0]] = s;
	while(!q.empty()) {
		int x = q.front();
		q.pop();
		for (int i = h[x]; i; i = e[i].ne) {
			int u = e[i].t;
			if (u == t) return true;
			if (!vi[u]) {
				vi[u] = true;
				rem[++rem[0]] = u;
				q.push(u);
			}
		}
	}
	return false;
}
int main() {
	freopen("treasure.in", "r", stdin);
	freopen("treasure.out", "w", stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> m >> k >> q;
	for (int i = 1; i <= n; i++) s[i].push_back('0');
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			cin >> c;
			s[i].push_back(c);
		}
	}
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			if (!vis[id(i, j)] && s[i][j] != '#') bfs(i, j, ++sum);
		}
	}
	int x1, x2, y1, y2;
	for (int i = 1; i <= k; i++) {
		cin >> x1 >> y1 >> x2 >> y2;
		if (belog[id(x1, y1)] != belog[id(x2, y2)]) add(belog[id(x1, y1)], belog[id(x2, y2)]);
	}
	for (int i = 1; i <= q; i++) {
		cin >> x1 >> y1 >> x2 >> y2;
		if (afs(belog[id(x1, y1)], belog[id(x2, y2)])) cout << 1 << '\n';
		else cout << 0 << '\n';
		for (int j = 1; j <= rem[0]; j++) vi[rem[j]] = false;
	}
	return 0;
}

序列 40pts

暴力40pts;

对于正解,首先维护出 $ a $ 和 $ b $ 的前缀和 $ suma $ 和 $ sumb $,然后对于一段区间,我们给它分成 $ [l, p], [p + 1, r] $ 两段子区间,然后分别取 $ \max $ 相加即可(比较人类智慧,不过还好)

对于 $ [p + 1, r] $ ,我们要求:

\[\max_{r = p + 1}^{n} suma_r - suma_{p + 1} - k \times sumb_r + k \times sumb_{p + 1} \]

也就是:

\[k \times sumb_{p + 1} - suma_{p + 1} + \max_{r = p + 1}^{n} -sumb_r \times k + suma_r \]

将 $ k $ 看作自变量 $ x $,发现后面的式子是关于 $ x $ 的一次函数,我们只需找出其当 $ x = k $ 时的最大值即可,这个用李超线段树是很好维护的;

左区间同理,式子推出来后发现只不过是把斜率和截距都取反了,所以我们维护一个最小值即可;

好像也可以维护凸包(类似斜率优化),但我不会;

注意直线有限制,所以我们要离线对其进行排序再插入;

发现我们要插入的直线条数是 $ n $ 条,而且只是插入直线,单点查询,所以时间复杂度为 $ \Theta(n \log n) $,常数较大,开 $ 1e6 $ 跑得较慢,空间也比较极限;

板子自己造的,所以有些冗长;

点击查看代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n, m;
long long a[1000005], b[1000005], suma[1000005], sumb[1000005];
long long ansl[1000005], ansr[1000005];
struct sss{
	long long p, k;
	int id;
	inline bool operator <(const sss &A) const {
		return p < A.p;
	}
}q[1000005];
inline bool cmp(sss x, sss y) {
	return x.p > y.p;
}
inline bool cmpx(sss x, sss y) {
	return x.id < y.id;
}
namespace LCSEG{
	inline int ls(int x) {
		return x << 1;
	}
	inline int rs(int x) {
		return x << 1 | 1;
	}
	struct sss{
		int l, r;
		long long k, b;
	}tr[8000005];
	void bt(int id, int l, int r) {
		tr[id].l = l;
		tr[id].r = r;
		tr[id].k = 1e18;
		tr[id].b = 1e18;
		if (l == r) return;
		int mid = (l + r) >> 1;
		bt(ls(id), l, mid);
		bt(rs(id), mid + 1, r);
	}
	void add(int s, int id, long long k, long long b) {
		if (tr[id].k == 1e18) {
			tr[id].k = k;
			tr[id].b = b;
			if (tr[id].l == tr[id].r) return;
			add(s, ls(id), k, b);
			add(s, rs(id), k, b);
		}
		int mid = (tr[id].l + tr[id].r) >> 1;
		if (s == 0) {
			long long mtr = tr[id].k * mid + tr[id].b;
			long long mli = k * mid + b;
			if (mtr < mli) {
				swap(tr[id].k, k);
				swap(tr[id].b, b);
			}
			long long ltr = tr[id].k * tr[id].l + tr[id].b;
			long long lli = k * tr[id].l + b;
			long long rtr = tr[id].k * tr[id].r + tr[id].b;
			long long rli = k * tr[id].r + b;
			if (ltr < lli) add(s, ls(id), k, b);
			else if (rtr < rli) add(s, rs(id), k, b);
		} else if (s == 1) {
			long long mtr = tr[id].k * mid + tr[id].b;
			long long mli = k * mid + b;
			if (mtr > mli) {
				swap(tr[id].k, k);
				swap(tr[id].b, b);
			}
			long long ltr = tr[id].k * tr[id].l + tr[id].b;
			long long lli = k * tr[id].l + b;
			long long rtr = tr[id].k * tr[id].r + tr[id].b;
			long long rli = k * tr[id].r + b;
			if (ltr > lli) add(s, ls(id), k, b);
			else if (rtr > rli) add(s, rs(id), k, b);
		}
	}
	long long ask(int s, int id, long long x) {
		if (tr[id].l == tr[id].r) return tr[id].k * x + tr[id].b;
		int mid = (tr[id].l + tr[id].r) >> 1;
		long long val = tr[id].k * x + tr[id].b;
		if (s == 0) {
			if (x <= mid) return max(val, ask(s, ls(id), x));
			else return max(val, ask(s, rs(id), x));
		} else {
			if (x <= mid) return min(val, ask(s, ls(id), x));
			else return min(val, ask(s, rs(id), x));
		}
	}
}
using namespace LCSEG;
int main() {
	freopen("seq.in", "r", stdin);
	freopen("seq.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] >> b[i];
		suma[i] = suma[i - 1] + a[i];
		sumb[i] = sumb[i - 1] + b[i];
	}
	bt(1, -1000000, 1000000);
	for (int i = 1; i <= m; i++) {
		cin >> q[i].p >> q[i].k;
		q[i].id = i;
	}
	sort(q + 1, q + 1 + m);
	int ls = 0;
	for (int i = 1; i <= m; i++) {
		for (int j = ls; j < q[i].p; j++) {
			add(1, 1, -sumb[j], suma[j]);
		}
		ansl[q[i].id] = ask(1, 1, q[i].k) * (-1);
		ls = q[i].p;
	}
	sort(q + 1, q + 1 + m, cmp);
	ls = n - 1;
	bt(1, -1000000, 1000000);
	add(0, 1, -sumb[n], suma[n]);
	for (int i = 1; i <= m; i++) {
		for (int j = ls; j > q[i].p; j--) {
			add(0, 1, -sumb[j], suma[j]);
		}
		ansr[q[i].id] = ask(0, 1, q[i].k);
		ls = q[i].p;
	}
	sort(q + 1, q + 1 + m, cmpx);
	for (int i = 1; i <= m; i++) {
		cout << max(ansl[i] + ansr[i], suma[q[i].p] - q[i].k * sumb[q[i].p] + ansl[i]) << '\n';
	}
	return 0;
}
posted @ 2024-10-05 12:11  Peppa_Even_Pig  阅读(21)  评论(0编辑  收藏  举报