目录
Contest Info
Solved | A | B | C | D | E | F |
---|---|---|---|---|---|---|
4/6 | O | O | O | O | - | - |
- O 在比赛中通过
- Ø 赛后通过
- ! 尝试了但是失败了
- - 没有尝试
Solutions
A. Save the Nature
题意:
有\(n\)个数\(p_i\)。
- 如果一个下标它是\(a\)的倍数,那么这个位置的价值就是\(a_i \cdot x\%\)
- 如果一个下标它是\(b\)的倍数,那么这个位置的价值就是\(a_i \cdot y\%\)
- 如果一个下标它是\(lcm(a, b)\)的倍数,那么这个位置的价值就是\(a_i \cdot (x + y)\%\)
现在可以给\(p_i\)重新排序,问排序最最少多少个前\(y\)个数,使得前\(y\)个数的价值和大于等于\(k\)。
思路:
二分答案,然后将大的贪心放在大的位置上。
代码:view code
#include <bits/stdc++.h> #define debug(...) { printf("# "); printf(__VA_ARGS__); puts(""); } #define fi first #define se second #define endl "\n" using namespace std; using db = double; using ll = long long; using ull = unsigned long long; using pII = pair <int, int>; using pLL = pair <ll, ll>; constexpr int mod = 1e9 + 7; template <class T1, class T2> inline void chadd(T1 &x, T2 y) { x += y; while (x >= mod) x -= mod; while (x < 0) x += mod; } template <class T1, class T2> inline void chmax(T1 &x, T2 y) { if (x < y) x = y; } template <class T1, class T2> inline void chmin(T1 &x, T2 y) { if (x > y) x = y; } inline int rd() { int x; cin >> x; return x; } template <class T> inline void rd(T &x) { cin >> x; } template <class T> inline void rd(vector <T> &vec) { for (auto &it : vec) cin >> it; } inline void pt() { cout << endl; } template <class T, class... Ts> void pt(const T& arg, const Ts&... args) { cout << arg << " "; pt(args...); } template <class T> inline void pt(const T &s) { cout << s << "\n"; } template <class T> inline void pt(const vector <T> &vec) { for (auto &it : vec) cout << it << " "; cout << endl; } ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; } inline ll qpow(ll base, ll n) { ll res = 1; while (n) { if (n & 1) res = res * base % mod; base = base * base % mod; n >>= 1; } return res; } constexpr int N = 2e5 + 10; int n, p[N], x, y, a, b; ll k; bool check(ll mid) { ll lcm = 1ll * a * b / gcd(a, b); ll cnt[3] = {mid / a - mid / lcm, mid / b - mid / lcm, mid / lcm}; ll tot = 0; for (int i = 1; i <= mid; ++i) { if (cnt[2]) { tot += 1ll * p[i] / 100 * (x + y); --cnt[2]; } else if (cnt[1]) { tot += 1ll * p[i] / 100 * y; --cnt[1]; } else if (cnt[0]) { tot += 1ll * p[i] / 100 * x; --cnt[0]; } else break; } return tot >= k; } void run() { cin >> n; for (int i = 1; i <= n; ++i) cin >> p[i]; sort(p + 1, p + 1 + n, [&](int x, int y) { return x > y; }); cin >> x >> a >> y >> b >> k; if (x > y) swap(x, y), swap(a, b); int l = 1, r = n, res = -1; while (r - l >= 0) { int mid = (l + r) >> 1; if (check(mid)) { res = mid; r = mid - 1; } else l = mid + 1; } pt(res); } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); cout << fixed << setprecision(20); int _T; cin >> _T; while (_T--) run(); return 0; }
B. Sequence Sorting
题意:
给出一个序列\(a_i\),每次可以选择一种数,将这种数全丢到前面或者全丢到后面。
问最少操作几次,使得该序列变成非降序。
思路:
考虑最多保留多少种数。显然保留下来的肯定是非降序的数,并且是连续的。
那么直接扫一遍即可。
代码:view code
#include <bits/stdc++.h> #define debug(...) { printf("# "); printf(__VA_ARGS__); puts(""); } #define fi first #define se second #define endl "\n" using namespace std; using db = double; using ll = long long; using ull = unsigned long long; using pII = pair <int, int>; using pLL = pair <ll, ll>; constexpr int mod = 1e9 + 7; template <class T1, class T2> inline void chadd(T1 &x, T2 y) { x += y; while (x >= mod) x -= mod; while (x < 0) x += mod; } template <class T1, class T2> inline void chmax(T1 &x, T2 y) { if (x < y) x = y; } template <class T1, class T2> inline void chmin(T1 &x, T2 y) { if (x > y) x = y; } inline int rd() { int x; cin >> x; return x; } template <class T> inline void rd(T &x) { cin >> x; } template <class T> inline void rd(vector <T> &vec) { for (auto &it : vec) cin >> it; } inline void pt() { cout << endl; } template <class T, class... Ts> void pt(const T& arg, const Ts&... args) { cout << arg << " "; pt(args...); } template <class T> inline void pt(const T &s) { cout << s << "\n"; } template <class T> inline void pt(const vector <T> &vec) { for (auto &it : vec) cout << it << " "; cout << endl; } ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; } inline ll qpow(ll base, ll n) { ll res = 1; while (n) { if (n & 1) res = res * base % mod; base = base * base % mod; n >>= 1; } return res; } constexpr int N = 3e5 + 10; int n, a[N], l[N], r[N]; void run() { cin >> n; memset(l, 0x3f, sizeof (l[0]) * (n + 10)); memset(r, 0, sizeof (r[0]) * (n + 10)); for (int i = 1; i <= n; ++i) { cin >> a[i]; chmin(l[a[i]], i); chmax(r[a[i]], i); } int res = 1, tot = 0; int lst = 0, sum = 0; for (int i = 1; i <= n; ++i) if (r[i] != 0) { ++tot; if (l[i] > lst) { lst = r[i]; ++sum; chmax(res, sum); } else { lst = r[i]; sum = 1; } } pt(tot - res); } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); cout << fixed << setprecision(20); int _T; cin >> _T; while (_T--) run(); return 0; }
C. Paint the Tree
题意:
给出一棵树,给每个点涂上\(k\)种颜色,一种颜色最多涂给两个点,但是有无限种颜色可以涂。
一条边的价值是如果它两个端点共有至少一种颜色,那么它的价值为它的权值,否则为\(0\)。
现在问整棵树所有边的价值和最大是多少,在最优涂色方案下。
思路:
\(f[i][0]\)表示\(i\)的子树中并且\(i\)没有一种颜色可以涂的最大价值,\(f[i][1]\)表示\(i\)的子树中并且\(i\)还剩了至少一种颜色可以涂的最大价值。
那么一个\(u\),它最多选择\(k\)个\(f[v][1] + w\)进行转移,我们先假设全都选\(f[v][0]\)转移,然后维护一个堆,里面放的是\(f[v][1] + w - f[v][0]\),贪心选取前\(k\)大即可。
代码:view code
#include <bits/stdc++.h> #define debug(...) { printf("# "); printf(__VA_ARGS__); puts(""); } #define fi first #define se second #define endl "\n" using namespace std; using db = double; using ll = long long; using ull = unsigned long long; using pII = pair <int, int>; using pLL = pair <ll, ll>; constexpr int mod = 1e9 + 7; template <class T1, class T2> inline void chadd(T1 &x, T2 y) { x += y; while (x >= mod) x -= mod; while (x < 0) x += mod; } template <class T1, class T2> inline void chmax(T1 &x, T2 y) { if (x < y) x = y; } template <class T1, class T2> inline void chmin(T1 &x, T2 y) { if (x > y) x = y; } inline int rd() { int x; cin >> x; return x; } template <class T> inline void rd(T &x) { cin >> x; } template <class T> inline void rd(vector <T> &vec) { for (auto &it : vec) cin >> it; } inline void pt() { cout << endl; } template <class T, class... Ts> void pt(const T& arg, const Ts&... args) { cout << arg << " "; pt(args...); } template <class T> inline void pt(const T &s) { cout << s << "\n"; } template <class T> inline void pt(const vector <T> &vec) { for (auto &it : vec) cout << it << " "; cout << endl; } ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; } inline ll qpow(ll base, ll n) { ll res = 1; while (n) { if (n & 1) res = res * base % mod; base = base * base % mod; n >>= 1; } return res; } constexpr int N = 5e5 + 10; int n, k, fa[N]; ll f[N][2], g[N]; vector <vector<pII>> G; void dfs(int u) { f[u][0] = f[u][1] = 0; for (auto &it : G[u]) { int v = it.fi, w = it.se; if (v == fa[u]) continue; fa[v] = u; dfs(v); g[v] = f[v][1] + w - f[v][0]; f[u][0] += f[v][0]; f[u][1] += f[v][0]; } vector <int> id; for (auto &it : G[u]) if (it.fi != fa[u]) id.push_back(it.fi); sort(id.begin(), id.end(), [&](int x, int y) { return g[x] > g[y]; }); for (int i = 0, sze = id.size(); i < k && i < sze; ++i) { int v = id[i]; if (g[v] < 0) break; if (i < k - 1) f[u][1] += g[v]; f[u][0] += g[v]; } } void run() { cin >> n >> k; G.clear(); G.resize(n + 1); for (int i = 1, u, v, w; i < n; ++i) { cin >> u >> v >> w; G[u].emplace_back(v, w); G[v].emplace_back(u, w); } fa[1] = 1; dfs(1); pt(max(f[1][0], f[1][1])); } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); cout << fixed << setprecision(20); int _T; cin >> _T; while (_T--) run(); return 0; }
D. Stack Exterminable Arrays
题意:
给出\(n\)个数,维护一个栈,将一个数列加到栈中,这么加:
- 如果栈空或者栈顶不等于当前数\(a_i\),那么将\(a_i\)加入到栈顶
- 如果栈顶的数等于当前数\(a_i\),那么栈顶弹出。
现在询问有多少连续子序列操作完后栈是空的。
思路:
我们考虑枚举每个连续子序列的右端点,统计有多少个左端点满足。
我们用\(S[i]\)表示前\(i\)个数的操作完后的栈序列。
那么当且仅当\(S[i] = S[j]\)的时候,\([i +1, j]\)这段序列操作完后栈是空的。
将\(S[i]\)哈希一下即可。
代码:view code
#include <bits/stdc++.h> #define debug(...) { printf("# "); printf(__VA_ARGS__); puts(""); } #define fi first #define se second #define endl "\n" using namespace std; using db = double; using ll = long long; using ull = unsigned long long; using pII = pair <int, int>; using pLL = pair <ll, ll>; constexpr int mod = 1e9 + 7; template <class T1, class T2> inline void chadd(T1 &x, T2 y) { x += y; while (x >= mod) x -= mod; while (x < 0) x += mod; } template <class T1, class T2> inline void chmax(T1 &x, T2 y) { if (x < y) x = y; } template <class T1, class T2> inline void chmin(T1 &x, T2 y) { if (x > y) x = y; } inline int rd() { int x; cin >> x; return x; } template <class T> inline void rd(T &x) { cin >> x; } template <class T> inline void rd(vector <T> &vec) { for (auto &it : vec) cin >> it; } inline void pt() { cout << endl; } template <class T, class... Ts> void pt(const T& arg, const Ts&... args) { cout << arg << " "; pt(args...); } template <class T> inline void pt(const T &s) { cout << s << "\n"; } template <class T> inline void pt(const vector <T> &vec) { for (auto &it : vec) cout << it << " "; cout << endl; } ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; } inline ll qpow(ll base, ll n) { ll res = 1; while (n) { if (n & 1) res = res * base % mod; base = base * base % mod; n >>= 1; } return res; } constexpr int N = 3e5 + 10; // struct Hash { static ull base[N]; static void init() { base[0] = 1; for (int i = 1; i < N; ++i) base[i] = base[i - 1] * 19260817; } ull a[N]; inline void work() { a[0] = 0; } inline void add(int ch, int id) { a[id] = a[id - 1] * 19260817 + ch; } }hs; ull Hash::base[N] = {0}; map <ull, int> mp; int n, a[N], sta[N]; void run() { cin >> n; for (int i = 1; i <= n; ++i) cin >> a[i]; mp.clear(); mp[0] = 1; *sta = 0; ll res = 0; hs.work(); for (int i = 1; i <= n; ++i) { if (*sta && sta[*sta] == a[i]) --*sta; else sta[++*sta] = a[i], hs.add(a[i], *sta); ull H = hs.a[*sta]; res += mp[H]; ++mp[H]; } pt(res); } int main() { Hash::init(); ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); cout << fixed << setprecision(20); int _T; cin >> _T; while (_T--) run(); return 0; }