Atcoder 279 A-F(二踢脚)
279:希望你有事儿(
A - C
签到题不讲……
但是他其实是签(du)到(liu)题
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;
}
拜!