目录
Contest Info
Solved | A | B | C | D | E | F | G |
---|---|---|---|---|---|---|---|
6/7 | O | O | Ø | Ø | Ø | - | Ø |
- O 在比赛中通过
- Ø 赛后通过
- ! 尝试了但是失败了
- - 没有尝试
Solutions
A. Pens and Pencils
签到。
B. Rooms and Staircases
签到。
C. The Football Season
题意:
给出\(n, p, w, d\),求解:
\[
\begin{eqnarray*}
x \cdot w + y \cdot d = p \\
x + y \leq n
\end{eqnarray*}
\]
题目保证\(d < w\)
思路:
题目保证了\(d < w\),那么有\(y < d\),因为如果\(y = d\),那么相当于\(w * d\),然后取了\(d\)个\(w\),那么不如取\(w\)个\(d\)更优。
所以直接暴力即可。
也可以直接上\(exgcd\),但是要讨论的东西挺多的。
代码:view code
#pragma GCC optimize("Ofast,unroll-loops,no-stack-protector,fast-math") #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native") #include <bits/stdc++.h> #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; } #define dbg(x...) do { cout << "\033[32;1m" << #x << " -> "; err(x); } while (0) void err() { cout << "\033[39;0m" << endl; } template <class T, class... Ts> void err(const T& arg, const Ts&... args) { cout << arg << ' '; err(args...); } template <template<typename...> class T, typename t, typename... A> void err(const T <t> &arg, const A&... args) { for (auto &v : arg) cout << v << ' '; err(args...); } inline void pt() { cout << endl; } template <class T, class... Ts> void pt(const T& arg, const Ts&... args) { cout << arg << ' '; pt(args...); } template <template<typename...> class T, typename t, typename... A> void pt(const T <t> &arg, const A&... args) { for (auto &v : arg) cout << v << ' '; pt(args...); } 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; } //head constexpr int N = 1e5 + 10; ll n, p, w, d, x, y; void run() { for (ll y = 0; y <= w; ++y) { if ((p - y * d) % w == 0) { x = (p - y * d) / w; if (x >= 0 && y >= 0 && x + y <= n) return pt(x, y, n - x - y); } } pt(-1); } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); cout << fixed << setprecision(20); while (cin >> n >> p >> w >> d) run(); return 0; }
exgcd代码:view code
import math def gcd(a, b): if b == 0: return a else: return gcd(b, a % b) def exgcd(a, b, X, Y): if a == 0 and b == 0: return -1 if b == 0: X[0] = 1 Y[0] = 0 return a d = exgcd(b, a % b, Y, X) Y[0] = Y[0] - a // b * X[0] return d def fceil(x, y): return (x + y - 1) // y def main(): n, p, w, d = map(int, input().split()); x = [0] y = [0] G = gcd(w, d) if p % G != 0: print(-1) return if p % w == 0: x[0] = p // w if x[0] <= n: print(x[0], 0, n - x[0]) return if p % d == 0: y[0] = p // d if y[0] <= n: print(0, y[0], n - y[0]) return exgcd(w, d, x, y) x[0] = x[0] * p // G y[0] = y[0] * p // G if x[0] < 0: t = fceil(abs(x[0]), d) x[0] = x[0] + d * t y[0] = y[0] - w * t if y[0] < 0: t = fceil(abs(y[0]), w) x[0] = x[0] - d * t y[0] = y[0] + w * t if x[0] < 0 or y[0] < 0: print(-1) return t = y[0] // w x[0] = x[0] + d * t y[0] = y[0] - w * t if x[0] + y[0] > n: print(-1) return z = n - x[0] - y[0] print(x[0], y[0], z) main()
D. Paint the Tree
题意:
给出\(n\)个点的树,有三种颜色,要给每个点染色,给出你每个点染某种颜色的代价。
染色方案要满足不存在任意一个三元组\((x, y, z)\)使得\(x, y\)有边相连,\(y, z\)有边相连,并且\(x, y, z\)有任意两个颜色相同。
求合法方案的最小代价。
思路:
考虑只有一条链的时候才存在方案,并且考虑在链上的话,前两个点的颜色确定了,那么整条链的颜色都确定了。
直接暴力枚举然后判断即可。
代码:view code
#pragma GCC optimize("Ofast,unroll-loops,no-stack-protector,fast-math") #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native") #include <bits/stdc++.h> #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; } #define dbg(x...) do { cout << "\033[32;1m" << #x << " -> "; err(x); } while (0) void err() { cout << "\033[39;0m" << endl; } template <class T, class... Ts> void err(const T& arg, const Ts&... args) { cout << arg << ' '; err(args...); } template <template<typename...> class T, typename t, typename... A> void err(const T <t> &arg, const A&... args) { for (auto &v : arg) cout << v << ' '; err(args...); } inline void pt() { cout << endl; } template <class T, class... Ts> void pt(const T& arg, const Ts&... args) { cout << arg << ' '; pt(args...); } template <template<typename...> class T, typename t, typename... A> void pt(const T <t> &arg, const A&... args) { for (auto &v : arg) cout << v << ' '; pt(args...); } 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; } //head constexpr int N = 1e5 + 10; int n, d[N], rt, col[N]; ll c[3][N], res, tot; vector <vector<int>> G; void dfs(int u, int fa) { for (auto &v : G[u]) if (v != fa) { col[v] = 3 - col[u] - col[fa]; dfs(v, u); } } ll fee() { ll res = 0; for (int i = 1; i <= n; ++i) res += c[col[i]][i]; return res; } bool ok() { for (int i = 1; i <= n; ++i) { if (d[i] == 1) rt = i; if (d[i] > 2) return false; } return true; } void run() { for (int i = 0; i < 3; ++i) for (int j = 1; j <= n; ++j) cin >> c[i][j]; memset(d, 0, sizeof d); G.clear(); G.resize(n + 1); for (int i = 1, u, v; i < n; ++i) { cin >> u >> v; ++d[u]; ++d[v]; G[u].push_back(v); G[v].push_back(u); } if (!ok()) return pt(-1); int a = 0, b = 0; res = 1e18; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { if (i != j) { col[rt] = i; col[G[rt][0]] = j; dfs(G[rt][0], rt); tot = fee(); if (tot < res) { res = tot; a = i, b = j; } } } } col[rt] = a; col[G[rt][0]] = b; dfs(G[rt][0], rt); pt(res); for (int i = 1; i <= n; ++i) cout << col[i] + 1 << " \n"[i == n]; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); cout << fixed << setprecision(20); while (cin >> n) run(); return 0; }
思路二:
考虑\(f[i][j][k]\)表示当前点为\(i\),前一个点的颜色为\(j\),当前点颜色为\(k\)的最小花费,然后转移即可。
但是输出方案要维护一个前驱或者直接确定了最后两个暴力推上去。
但是不能通过判断\(dp\)值来找前驱,这样可能导致染色方案不合法,但是\(dp\)值可能是相同的
E. Minimizing Difference
题意:
给出\(n\)个数\(a_i\),每次可以对一个数增加\(1\)或者减少\(1\)。问操作次数不小于\(k\)的情况下,\(n\)个数中的最大值减最小值的差值最小是多少
思路:
二分答案,然后考虑合法方案一定能让最大值或者最小值固定在某个\(a_i\),然后枚举\(a_i\),算右界范围内的花费是否小于等于\(k\)即可。
代码:view code
#pragma GCC optimize("Ofast,unroll-loops,no-stack-protector,fast-math") #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native") #include <bits/stdc++.h> #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; } #define dbg(x...) do { cout << "\033[32;1m" << #x << " -> "; err(x); } while (0) void err() { cout << "\033[39;0m" << endl; } template <class T, class... Ts> void err(const T& arg, const Ts&... args) { cout << arg << ' '; err(args...); } template <template<typename...> class T, typename t, typename... A> void err(const T <t> &arg, const A&... args) { for (auto &v : arg) cout << v << ' '; err(args...); } inline void pt() { cout << endl; } template <class T, class... Ts> void pt(const T& arg, const Ts&... args) { cout << arg << ' '; pt(args...); } template <template<typename...> class T, typename t, typename... A> void pt(const T <t> &arg, const A&... args) { for (auto &v : arg) cout << v << ' '; pt(args...); } 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; } //head constexpr int N = 1e5 + 10; int n; ll a[N], S[N], k; ll get(int l, int r) { if (l > r) return 0; return S[r] - S[l - 1]; } ll fee(int l, int r) { return a[l] * l - get(1, l) + get(r, n) - a[r] * (n - r + 1); } bool check(ll x) { ll tot = 1e18; int pos = 1; for (int i = 1; i <= n; ++i) { if (pos < i) pos = i; while (pos <= n && a[i] + x >= a[pos]) ++pos; ll now = a[i] * i - get(1, i) + get(pos, n) - (a[i] + x) * (n - pos + 1); chmin(tot, now); } pos = n; for (int i = n; i >= 1; --i) { if (pos > n) pos = i; while (pos >= 1 && a[i] - x <= a[pos]) --pos; ll now = get(i, n) - a[i] * (n - i + 1) - get(1, pos) + (a[i] - x) * pos; chmin(tot, now); } return tot <= k; } void run() { for (int i = 1; i <= n; ++i) cin >> a[i]; sort(a + 1, a + 1 + n); for (int i = 1; i <= n; ++i) S[i] = S[i - 1] + a[i]; ll l = 0, r = a[n] - a[1], res = r; while (r - l >= 0) { ll 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); while (cin >> n >> k) run(); return 0; }
G. Running in Pairs
题意:
要求构造两个排列\(p, q\),使得\(sum = \sum\limits_{i = 1}^n max(p_i, q_i) \leq k\),并且结果最大。
思路:
考虑将第一个排列顺序排放。
然后考虑第二个排列刚开始也是顺序排放的。
然后考虑交换位置视为元素左移和元素右移。
显然,元素右移不会对答案产生影响。
但是元素左移,左移几个位置它就产生多少贡献。
那么显然可以发现这个变化是连续的,直接贪心即可。
代码:view code
#pragma GCC optimize("Ofast,unroll-loops,no-stack-protector,fast-math") #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native") #include <bits/stdc++.h> #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; } #define dbg(x...) do { cout << "\033[32;1m" << #x << " -> "; err(x); } while (0) void err() { cout << "\033[39;0m" << endl; } template <class T, class... Ts> void err(const T& arg, const Ts&... args) { cout << arg << ' '; err(args...); } template <template<typename...> class T, typename t, typename... A> void err(const T <t> &arg, const A&... args) { for (auto &v : arg) cout << v << ' '; err(args...); } inline void pt() { cout << endl; } template <class T, class... Ts> void pt(const T& arg, const Ts&... args) { cout << arg << ' '; pt(args...); } template <template<typename...> class T, typename t, typename... A> void pt(const T <t> &arg, const A&... args) { for (auto &v : arg) cout << v << ' '; pt(args...); } 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; } //head constexpr int N = 1e6 + 10; int n, a[N]; ll k; void run() { ll base = 1ll * n * (n + 1) / 2; if (base > k) return pt(-1); for (int i = 1; i <= n; ++i) a[i] = i; ll remind = k - 1ll * n * (n + 1) / 2; int low = 1; for (int i = n; i >= 1 && i > low; --i) { if (i - low <= remind) { remind -= i - low; swap(a[i], a[low]); ++low; } else { swap(a[i], a[i - remind]); remind = 0; break; } } pt(k - remind); for (int i = 1; i <= n; ++i) cout << i << " \n"[i == n]; for (int i = 1; i <= n; ++i) cout << a[i] << " \n"[i == n]; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); cout << fixed << setprecision(20); while (cin >> n >> k) run(); return 0; }