AtCoder Beginner Contest 368
A - Cut (abc368 A)
题目大意
给定一个数组,将右边个数保持原顺序挪到左边,输出。
解题思路
即从左边第个数开始输出即可。或者用rotate
函数转换一下。
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n, k; cin >> n >> k; k = n - k; vector<int> a(n); for (auto& i : a) cin >> i; rotate(a.begin(), a.begin() + k, a.end()); for (auto i : a) cout << i << ' '; cout << '\n'; return 0; }
B - Decrease 2 max elements (abc368 B)
题目大意
给定一个数组,每次将最大的两个数减一,直到只有一个或无正数。输出操作的次数。
解题思路
最多个数,每个数最大 ,因此最大的操作次数只有,加上每次操作的复杂度是 ,因此直接模拟的复杂度即为 ,能过。
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n; cin >> n; vector<int> a(n); for (auto& i : a) cin >> i; int cnt = 0; while (count_if(a.begin(), a.end(), [](int x) { return x > 0; }) > 1) { sort(a.begin(), a.end(), greater<int>()); a[0]--; a[1]--; cnt++; } cout << cnt << '\n'; return 0; }
C - Triple Attack (abc368 C)
题目大意
个怪兽血量 ,依次打它们。当前怪物死了则打下一个。
初始时刻,每时刻都会对当前怪物造成 的伤害,如果 ,则可以额外造成 的伤害(即一共 的伤害)。
问打死所有怪物时的时刻。
解题思路
直接模拟时刻流逝,其最大时刻高达,但注意到打怪物的时刻越多,伤害越高,因此对于每个怪兽,我们不必模拟时刻流逝,而是二分打死怪物的时刻 ,看看时间的伤害是否足够打死当前怪兽。
对每个怪兽都二分求出一下打死的时刻,最后的二分结果即为答案。
计算 时间的伤害,即为
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n; cin >> n; LL t = 0; LL up = 1e18; auto check = [](LL l, LL r) -> LL { return r - l + 2ll * (r / 3 - l / 3); }; auto solve = [&](LL t, int x) -> LL { LL l = t, r = up; while (l + 1 < r) { LL mid = (l + r) / 2; if (check(t, mid) < x) l = mid; else r = mid; } return r; }; while (n--) { int x; cin >> x; t = solve(t, x); } cout << t << '\n'; return 0; }
D - Minimum Steiner Tree (abc368 D)
题目大意
给定一棵树,问保留个点且连通的最小点数是多少。
解题思路
以第一个保留的点为根,进行。
在 过程中的当前点 ,判断其是否需要保留,则需要知道其子树是否有需要保留的点,有则当前点 需要保留。
因此 返回的东西即为该子树是否有需要保留的点
。最后答案就是 fixed
点的数量。
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n, k; cin >> n >> k; vector<vector<int>> edge(n); for (int i = 0; i < n - 1; i++) { int u, v; cin >> u >> v; u--; v--; edge[u].push_back(v); edge[v].push_back(u); } vector<int> fix(n, 0); int root = 0; for (int i = 0; i < k; ++i) { cin >> root; --root; fix[root] = 1; } int ans = 0; auto dfs = [&](auto dfs, int u, int fa) -> bool { bool fixed = fix[u]; for (auto v : edge[u]) { if (v == fa) continue; fixed |= dfs(dfs, v, u); } ans += fixed; return fixed; }; dfs(dfs, root, root); cout << ans << '\n'; return 0; }
E - Train Delay (abc368 E)
题目大意
给定个城市和 个火车的信息,从,时间是 。
先给定 ,即第一个城市火车延误出发时间,要求 ,使得:
- 对于任意两个火车信息满足 的,也满足,即原来可换乘的俩列车, 在延误后仍可换乘。
- 最小
解题思路
<++>
神奇的代码
F - Dividing Game (abc368 F)
题目大意
给定个数, 杏菜和 玩游戏, 先。
每轮,选一个数,将其变为真因子。
无法操作即输。问最优情况下谁赢。
解题思路
知道博弈论的知识就可以解了。
每个数之间是互不干扰的,因此每个数可以视为一个独立局面,因此整个局面的值就是每个独立局面的 值的异或。
考虑一个独立局面的 值怎么求,即 。根据 值定义,其为所有后继情况的 值的 ,即 。
枚举因子数是,而 ,因此花预处理出所有数的值,然后异或一下,为 则 先手输,否则 先手赢。
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int N = 1e5 + 8; vector<int> sg(N); sg[1] = 0; auto getSG = [&](int x) { set<int> hold{sg[1]}; for (int i = 2; i * i <= x; ++i) { if (x % i == 0) { hold.insert(sg[x / i]); hold.insert(sg[i]); } } for (int i = 0; i < N; ++i) { if (hold.find(i) == hold.end()) { return i; } } assert(0); }; for (int i = 2; i < N; ++i) { sg[i] = getSG(i); } int n; cin >> n; int ans = 0; for (int i = 0; i < n; ++i) { int x; cin >> x; ans ^= sg[x]; } if (ans) { cout << "Anna" << '\n'; } else { cout << "Bruno" << '\n'; } return 0; }
G - Add and Multiply Queries (abc368 G)
题目大意
给定两个数组,维护下列三种操作:
1 i x
,令2 i x
,令3 l r
,求最大值,其初始 ,依次 ,令或
题目保证操作三的答案不超过。
解题思路
对于一次操作,很显然对于 ,我令。一次的复杂度是 。
注意到操作三的答案不超过,这意味着什么呢。
首先,如果 ,我们很显然是选择操作 ,而对于要判断最大值的,必定有 , ,也就是说,每做一次判断, 都会翻倍,最多翻 次,就达到 了。
所以,每次区间 中,实际上只有最多个 ,其余都是 ,这意味着都会选择 。
因此每次操作区间 ,我们直接模拟,
- 找到第一个
- 处理 的操作,即
- 处理 的操作,即
- ,重复第一个操作
最多跑 次就跑完了,因为带修改,第一步操作就用线段树上二分,通过区间最大值>1
找到其位置,第二步操作就是一个区间和。
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; const int N = 2e5 + 8; class info { public: LL sum; int maxx; info(LL sum = 0, int maxx = 0) : sum(sum), maxx(maxx) {} info operator+(const info& rhs) const { return info(sum + rhs.sum, max(maxx, rhs.maxx)); } }; class segment { #define lson (root << 1) #define rson (root << 1 | 1) public: info val[N << 2]; void build(int root, int l, int r, vector<int>& a, vector<int>& b) { if (l == r) { val[root] = info(a[l], b[l]); return; } int mid = (l + r) >> 1; build(lson, l, mid, a, b); build(rson, mid + 1, r, a, b); val[root] = val[lson] + val[rson]; } void update(int root, int l, int r, int pos, info& v) { if (l == r) { val[root] = v; return; } int mid = (l + r) >> 1; if (pos <= mid) update(lson, l, mid, pos, v); else update(rson, mid + 1, r, pos, v); val[root] = val[lson] + val[rson]; } info query(int root, int l, int r, int L, int R) { if (L <= l && r <= R) { return val[root]; } int mid = (l + r) >> 1; info resl{}, resr{}; if (L <= mid) resl = query(lson, l, mid, L, R); if (R > mid) resr = query(rson, mid + 1, r, L, R); return resl + resr; } int findfirst(int root, int l, int r, int L, int R) { if (l > R || r < L) { return 0; } if (L <= l && r <= R && val[root].maxx < 2) { return 0; } if (l == r) { return l; } int mid = (l + r) >> 1; int ret = findfirst(lson, l, mid, L, R); if (ret == 0) { ret = findfirst(rson, mid + 1, r, L, R); } return ret; } } seg; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n; cin >> n; vector<int> a(n + 1); for (int i = 1; i <= n; ++i) cin >> a[i]; vector<int> b(n + 1); for (int i = 1; i <= n; ++i) cin >> b[i]; seg.build(1, 1, n, a, b); int q; cin >> q; while (q--) { int op; cin >> op; if (op == 1) { int pos, x; cin >> pos >> x; a[pos] = x; info v(a[pos], b[pos]); seg.update(1, 1, n, pos, v); } else if (op == 2) { int pos, x; cin >> pos >> x; b[pos] = x; info v(a[pos], b[pos]); seg.update(1, 1, n, pos, v); } else { int l, r; cin >> l >> r; LL ans = a[l]; l++; while (l <= r) { int pos = seg.findfirst(1, 1, n, l, r); if (pos == 0) { ans += seg.query(1, 1, n, l, r).sum; break; } else { info v = seg.query(1, 1, n, l, pos - 1); ans += v.sum; ans = max(ans + a[pos], ans * b[pos]); l = pos + 1; } } cout << ans << '\n'; } } return 0; }
本文作者:~Lanly~
本文链接:https://www.cnblogs.com/Lanly/p/18378487
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
2017-08-24 JZOJ.5335【NOIP2017模拟8.24】早苗