Atcoder 279 A-F(二踢脚)

279:希望你有事儿(

A - C

签到题不讲……
但是他其实是签(du)到(liu)题
image

D

If you know at least 3 of these things and you are not red — you are doing it wrong. Stop learning useless algorithms, go and solve some problems, learn how to use binary search.
——$ \color{black}U\color{red}{m\_nik} $

但今天我们讲的是三分……
让英雄 Takahashi 降落到地面(在此之前,他让 $ g := x + 1 $ 了)的时间为 $ f(x) = Bx + \frac{A}{\sqrt[2]{x + 1}} $
不难发现函数 $ f(x) $ 变成图像将会是一个波谷,两遍单调上升/下降。
那我们让 $ m_1 = \frac{2l + r}{3}, m_2 = \frac{l + 2r}{3} $ 。
如果 $ f(m_1) > f(m_2) $ 则让 $ l = m_1 $ ,否则让 $ r = m_2 $ 。
如果波谷不在 $ m_1 \sim m_2 $ 之间,那就按照那个方向找波谷,否则哪个缩小都行。

#include <bits/stdc++.h>
using namespace std;

double a, b;

double f(double train) {
	return train * b + a / sqrt(train + 1);
}

int main() {
	cin >> a >> b;
	double l = 0, r = 0x3f3f3f3f3f3f3f3fll + 0.0;
	for (int i = 0; i < 10000; i++) {
		double m1 = (2 * l + r) / 3.0;
		double m2 = (l + 2 * r) / 3.0;
		if (f(m1) > f(m2)) {
			l = m1;
		} else {
			r = m2;
		}
	}
	cout << fixed << setprecision(10) << min(f((long long)l), f((long long)l + 1));
	return 0;
}

E

首先暴力模拟一遍,看 $ B_i $ 下标,$ i $ 在 $ B $ 里的位置记为 $ c_i $。
记录每次交换的两个数,记为 $ pos_{i, 1} $ 与 $ pos_{i, 2} $ 。
当跳过第 $ i $ 次交换时:

  • $ pos_{i, 1} \neq 1 $ 且 $ pos_{i, 2} \neq 1 $ :答案为 $ c_1 $ 。
  • $ pos_{i, 1} = 1 $ :答案为 $ c_{pos_{i, 2}} $ 。
  • $ pos_{i, 2} = 1 $ :答案为 $ c_{pos_{i, 1}} $ 。
#include <bits/stdc++.h>
using namespace std;

int a[200005], b[200005], change[200005][2], pos[200005];

int main() {
	int n, m;
	scanf("%d %d", &n, &m);
	for (int i = 0; i < n; i++) {
		b[i] = i;
	}
	for (int i = 0; i < m; i++) {
		scanf("%d", &a[i]);
		a[i]--;
		change[i][0] = b[a[i]];
		change[i][1] = b[a[i] + 1];
		swap(b[a[i]], b[a[i] + 1]);
	}
	for (int i = 0; i < n; i++) {
		pos[b[i]] = i;
	}
	for (int i = 0; i < m; i++) {
		if (change[i][0] != 0 && change[i][1] != 0) {
			printf("%d\n", pos[0] + 1);
		} else if (change[i][0] == 0) {
			printf("%d\n", pos[change[i][1]] + 1);
		} else {
			printf("%d\n", pos[change[i][0]] + 1);
		}
	}
	return 0;
}

F

重头戏来了!!!
以及一篇 CF 博客:RE 判成 WA
并查集预定。。。。。。


一个一个看!

type 1

用并查集做。
把 $ Y $ 的那堆的根的父亲设为 $ X $ 那堆的根。
然后 $ Y $ 这堆只能另寻其路,换成新箱子编号(不然做 type 2 会出问题)

type 2

设一个数组 $ idx $ ,让 $ idx_i $ 为 $ i $ 所在的那堆。
那么就让 $ idx_{k + 1} = x $ 好了。

type 3

直接输出 $ idx_x $ 的就行了。


上代码!

#include <bits/stdc++.h>
using namespace std;

int fa[600005];

void init() {
	memset(fa, -1, sizeof fa);
}

int find_root(int x) {
	if (fa[x] == -1) {
		return x;
	}
	return fa[x] = find_root(fa[x]);
}

void unite(int x, int y) {
	if (find_root(x) != find_root(y) && find_root(x) != -1) {
		fa[find_root(x)] = find_root(y);
	}
}

int now[300005], idx[600005], past[600005];

int main() {
	init();
	int n, q;
	scanf("%d %d", &n, &q);
	for (int i = 0; i < n; i++) {
		now[i] = i;
		past[i] = i;
		idx[i] = i;
	}
	int cntn = n - 1;
	int cnt = n - 1;
	while (q--) {
		int tp;
		scanf("%d", &tp);
		if (tp == 1) {
			int x, y;
			scanf("%d %d", &x, &y);
			x--, y--;
			unite(now[y], now[x]);
			now[y] = ++cntn;
			past[cntn] = y;
		} else if (tp == 2) {
			int x;
			scanf("%d", &x);
			x--;
			idx[++cnt] = now[x];
		} else {
			int x;
			scanf("%d", &x);
			x--;
			printf("%d\n", past[find_root(idx[x])] + 1);
		}
//		for (int i = 0; i < n; i++) {
//			cerr << now[i] << " ";
//		}
//		cerr << endl;
	}
	return 0;
}

拜!

posted @ 2022-11-27 21:45  A-Problem-Solver  阅读(37)  评论(0编辑  收藏  举报