- Contest Info
- Solutions
- Problem A. Accurate Movement
- Problem B. Bad Treap
- Problem E. Equidistant
- Problem H. High Load Database
- Problem I. Ideal Pyramid
- Problem J. Just the Last Digit
- Problem K. King’s Children
- Problem M. Managing Difficulties
Contest Info
Practice Link
Solved | A | B | C | D | E | F | G | H | I | J | K | L | M |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
8/13 | O | O | - | - | O | - | - | O | O | O | Ø | - | O |
- O 在比赛中通过
- Ø 赛后通过
- ! 尝试了但是失败了
- - 没有尝试
Solutions
Problem A. Accurate Movement
签到题。
代码:
view code#include <bits/stdc++.h> using namespace std; int ceil(int x, int y) { return (x + y - 1) / y; } int main() { int a, b, n; while (scanf("%d%d%d", &a, &b, &n) != EOF) { int res = ceil(n - b, b - a) + ceil(n - a, b - a); printf("%d\n", res); } return 0; }
Problem B. Bad Treap
题意:
令Treap的一对二维点权为\((f, sin(x))\),现在要给出\(n\)个\(x\),使得这个Treap的深度最大
思路:
考虑很小的时候,\(x = sin(x)\),那么它两维都是单调的,深度最大
代码:
view code#include <bits/stdc++.h> using namespace std; int main() { int n; scanf("%d", &n); for (long long i = 1; i <= n; ++i) printf("%lld\n", i * 710 - 710 * 25000); return 0; }
Problem E. Equidistant
题意:
给出一棵树,再给定\(m\)个点,现在要找一个点,使得这个点到\(m\)个点的距离相等
思路:
以\(m\)个点作为起点跑多源最短路,但是同时要记录到点\(x\)的最短路径条数,当最短路径条数为\(m\)的时候,那么这个点就是合法的
代码:
view code#include <bits/stdc++.h> using namespace std; const int N = 2e5 + 10; int n, m; int dep[N], sze[N], a[N], vis[N]; vector<vector<int> >G; void gao() { queue<int> q; for (int i = 1; i <= m; ++i) q.push(a[i]); while (!q.empty()) { int u = q.front(); q.pop(); for (auto &v : G[u]) { if (dep[v] == 0 || dep[v] == dep[u] + 1) { dep[v] = dep[u] + 1; sze[v] += sze[u]; if (sze[v] == m) { printf("YES\n%d\n", v); return ; } if (!vis[v]) { q.push(v); vis[v] = 1; } } } } puts("NO"); } int main() { while (scanf("%d %d", &n, &m) != EOF) { G.clear(); G.resize(n + 1); memset(dep, 0, sizeof dep); memset(sze, 0, sizeof sze); memset(vis, 0, sizeof vis); for (int i = 1, u, v; i < n; ++i) { scanf("%d %d", &u, &v); G[u].push_back(v); G[v].push_back(u); } for (int i = 1; i <= m; ++i) { scanf("%d", a + i); dep[a[i]] = 1; sze[a[i]] = 1; vis[a[i]] = 1; } if (n == 1) { puts("YES\n1"); } else { gao(); } } return 0; }
Problem H. High Load Database
题意:
给出\(n\)个数\(a_i(\sum a_i \leq 10^6)\),\(q\)次询问给出一个\(t_i\),问将这\(n\)个数分成若干个连续段,使得每段之和不超过\(t_i\)的最小段数
思路:
考虑单次询问显然可以贪心合并,但是我们可以维护一个前缀和,每次二分跳下一个位置,所以处理一个询问的时间是\(O(\text{段数}logn)\)。
并且考虑\(\sum a_i \leq 10^6\),所以所有可行询问的总段数不会很多,直接暴力即可。
代码:
view code#include <bits/stdc++.h> using namespace std; const int N = 1e6 + 10; int n, q, Max, a[N], sum[N], ans[N], vis[N]; int getans(int limit) { if (vis[limit]) return ans[limit]; vis[limit] = 1; if (Max > limit) { return ans[limit] = -1; } if (limit <= 1000) { int res = 1, pre = 0; for (int i = 1; i <= n; ++i) { if (a[i] + pre <= limit) { pre += a[i]; } else { pre = a[i]; ++res; } } return ans[limit] = res; } else { int res = 0, pos = 0; while (pos < n) { ++res; int nx = upper_bound(sum + 1, sum + 1 + n, limit + sum[pos]) - sum - 1; pos = nx; } return ans[limit] = res; } } int main() { while (scanf("%d", &n) != EOF) { memset(vis, 0, sizeof vis); sum[0] = 0; for (int i = 1; i <= n; ++i) { scanf("%d", a + i); Max = max(Max, a[i]); sum[i] = sum[i - 1] + a[i]; } scanf("%d", &q); while (q--) { int need; scanf("%d", &need); int res = getans(need); if (res == -1) puts("Impossible"); else printf("%d\n", res); } } return 0; }
Problem I. Ideal Pyramid
代码:
view code#include <bits/stdc++.h> using namespace std; const int N = 1e5 + 10; const int INF = 0x3f3f3f3f; struct node { int x, y, z; node() {} node(int x, int y, int z): x(x), y(y), z(z) {} }a[N]; int n; int x, y; bool ok(int h) { int l = -INF, r = INF, u = INF, d = -INF; for (int i = 1; i <= n; ++i) { if (h < a[i].z) return false; int x = h - a[i].z; l = max(l, a[i].x - x); r = min(r, a[i].x + x); u = min(u, a[i].y + x); d = max(d, a[i].y - x); } if (l > r || d > u) return false; x = l, y = d; return true; } int main() { while (scanf("%d", &n) != EOF) { for (int i = 1; i <= n; ++i) { scanf("%d %d %d", &a[i].x, &a[i].y, &a[i].z); } int l = 0, r = INF, res = INF; x = INF, y = INF; while (r - l >= 0) { int mid = (l + r) >> 1; if (ok(mid)) { r = mid -1; res = mid; } else { l = mid + 1; } } ok(res); printf("%d %d %d\n", x, y, res); } return 0; }
Problem J. Just the Last Digit
题意:
有一个\(n\)个点的有向图,\(i\) 到 \(j\)有边,那么必然有\(i < j\)。
现在给出\(a_{i, j} = i \rightarrow j\)的路径条数模\(10\)的结果,要你还原这个图。
思路:
正着推,考虑新加入一个点\(k\)的时候,我们枚举一个点\(i(i < k)\),如果\(i\)到\(k\)通过点\(j(i < j < k)\)中转的路径之和模\(10\)不等于\(a_{i, j}\),那么\(i \rightarrow k\)这条边是存在的,否则不存在
代码:
view code#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 510; int n; char a[N][N]; int res[N][N]; int main() { while (scanf("%d", &n) != EOF) { memset(res, 0, sizeof res); for (int i = 1; i <= n; ++i) { for (int j = 1; j <= n; ++j) { scanf(" %c", &a[i][j]); } } for (int i = 1; i <= n; ++i) { for (int j = i + 1; j <= n; ++j) { int sum = 0; for (int k = i + 1; k < j; ++k) { if (res[i][k]) sum += a[k][j] - '0'; } if ((sum + 1) % 10 == a[i][j] - '0') res[i][j] = 1; } } for (int i = 1; i <= n; ++i) { for (int j = 1; j <= n; ++j) { printf("%d", res[i][j]); } puts(""); } } return 0; }
Problem K. King’s Children
题意:
给出一个\(n \cdot m\)的矩形,上面的'.'表示空地,字母表示国王的儿子,'A'表示大儿子。
现在要给每个儿子划分城市,每个城市必须是一个矩形,每块空地只能属于一个城市,一个城市里面只能包含一个儿子。
但是大儿子划分得到的空地数量要尽可能的多,但不一定是最多。
思路:
对'A'找一个极大子矩形,挖空后将剩下的分完。
考虑两种分法:
- 先竖向扩展,然后横向扩展
- 先横向扩展,然后竖向扩展
这两种分法不可能同时不成立,不太知道为啥(猜的)。。
代码:
view code#include <bits/stdc++.h> using namespace std; #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...); } const int N = 1e3 + 10; const int INF = 0x3f3f3f3f; int n, m, ax, ay; char str[N][N], stra[N][N], strb[N][N]; int up[N][N], down[N][N]; int X[N], Y[N]; void gaoA(char str[][N], int l, int r) { int MinU = INF, MinD = INF; for (int i = l; i <= r; ++i) { MinU = min(MinU, up[ax][i]); MinD = min(MinD, down[ax][i]); } for (int i = l; i <= r; ++i) { for (int j = 1; j <= MinU; ++j) { str[ax - j + 1][i] = 'a'; } for (int j = 1; j <= MinD; ++j) { str[ax + j - 1][i] = 'a'; } } str[ax][ay] = 'A'; } void gaoU(char str[][N]) { for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { if (str[i][j] > 'A' && str[i][j] <= 'Z') { up[i][j] = i; for (int o = 1; ; ++o) { if (i - o < 1) break; if (str[i - o][j] != '.') break; up[i][j] = i - o; str[i - o][j] = str[i][j] - 'A' + 'a'; } } } } } void gaoD(char str[][N]) { for (int i = 1; i <= n; ++i) { for (int j = m; j >= 1; --j) { if (str[i][j] > 'A' && str[i][j] <= 'Z') { down[i][j] = i; for (int o = 1; ; ++o) { if (i + o > n) break; if (str[i + o][j] != '.') break; down[i][j] = i + o; str[i + o][j] = str[i][j] - 'A' + 'a'; } } } } } void gaoL(char str[][N]) { for (int j = 1; j <= m; ++j) { for (int i = 1; i <= n; ++i) { if (str[i][j] > 'A' && str[i][j] <= 'Z') { for (int o = j - 1; o >= 1; --o) { int F = 1; for (int k = up[i][j]; k <= down[i][j]; ++k) { if (str[k][o] != '.') { F = 0; break; } } if (!F) break; for (int k = up[i][j]; k <= down[i][j]; ++k) { str[k][o] = str[i][j] - 'A' + 'a'; } } } } } } void gaoR(char str[][N]) { for (int j = m; j >= 1; --j) { for (int i = 1; i <= n; ++i) { if (str[i][j] > 'A' && str[i][j] <= 'Z') { for (int o = j + 1; o <= m; ++o) { int F = 1; for (int k = up[i][j]; k <= down[i][j]; ++k) { if (str[k][o] != '.') { F = 0; break; } } if (!F) break; for (int k = up[i][j]; k <= down[i][j]; ++k) { str[k][o] = str[i][j] - 'A' + 'a'; } } } } } } void gaoU1(char str[][N]) { for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { if (str[i][j] > 'A' && str[i][j] <= 'Z') { for (int o = i - 1; o >= 1; --o) { int F = 1; for (int k = up[i][j]; k <= down[i][j]; ++k) { if (str[o][k] != '.') { F = 0; break; } } if (!F) break; for (int k = up[i][j]; k <= down[i][j]; ++k) { str[o][k] = str[i][j] - 'A' + 'a'; } } } } } } void gaoD1(char str[][N]) { for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { if (str[i][j] > 'A' && str[i][j] <= 'Z') { for (int o = i + 1; o <= n; ++o) { int F = 1; for (int k = up[i][j]; k <= down[i][j]; ++k) { if (str[o][k] != '.') { F = 0; break; } } if (!F) break; for (int k = up[i][j]; k <= down[i][j]; ++k) { str[o][k] = str[i][j] - 'A' + 'a'; } } } } } } void gaoL1(char str[][N]) { for (int j = 1; j <= m; ++j) { for (int i = 1; i <= n; ++i) { if (str[i][j] > 'A' && str[i][j] <= 'Z') { up[i][j] = j; for (int o = 1; ; ++o) { if (j - o < 1) break; if (str[i][j - o] != '.') break; up[i][j] = j - o; str[i][j - o] = str[i][j] - 'A' + 'a'; } } } } } void gaoR1(char str[][N]) { for (int j = m; j >= 1; --j) { for (int i = 1; i <= n; ++i) { if (str[i][j] > 'A' && str[i][j] <= 'Z') { down[i][j] = j; for (int o = 1; ; ++o) { if (j + o > m) break; if (str[i][j + o] != '.') break; down[i][j] = j + o; str[i][j + o] = str[i][j] - 'A' + 'a'; } } } } } void print(char str[][N]) { for (int i = 1; i <= n; ++i) printf("%s\n", str[i] + 1); } bool ok(char str[][N]) { for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { if (str[i][j] == '.') return false; } } return true; } int main() { while (scanf("%d %d", &n, &m) != EOF) { for (int i = 1; i <= n; ++i) { scanf("%s", str[i] + 1); } for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { if (str[i][j] == 'A') { ax = i, ay = j; } } } for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { if (i == 1) { if (str[i][j] == '.' || str[i][j] == 'A') up[i][j] = 1; else up[i][j] = 0; } else { if (str[i][j] == '.' || str[i][j] == 'A') up[i][j] = up[i - 1][j] + 1; else up[i][j] = 0; } } } for (int i = n; i >= 1; --i) { for (int j = 1; j <= m; ++j) { if (i == n) { if (str[i][j] == '.' || str[i][j] == 'A') down[i][j] = 1; else down[i][j] = 0; } else { if (str[i][j] == '.' || str[i][j] == 'A') down[i][j] = down[i + 1][j] + 1; else down[i][j] = 0; } } } // get A size int Max = -1, Maxl = -1 ,Maxr = -1; for (int l = 1; l <= m; ++l) { int MinU = INF, MinD = INF; for (int r = l; r <= m; ++r) { MinU = min(MinU, up[ax][r]); MinD = min(MinD, down[ax][r]); if (r >= ay && l <= ay) { if (Max < (r - l + 1) * (MinU + MinD - 1)) { Maxl = l, Maxr = r, Max = (r - l + 1) * (MinU + MinD - 1); } } } } // color A size gaoA(str, Maxl, Maxr); for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { stra[i][j] = str[i][j]; strb[i][j] = str[i][j]; } } gaoU(stra); gaoD(stra); gaoL(stra); gaoR(stra); gaoL1(strb); gaoR1(strb); gaoU1(strb); gaoD1(strb); if (ok(strb)) print(strb); else if (ok(stra)) print(stra); else assert(0); } return 0; }
Problem M. Managing Difficulties
签到题。
代码:
view code#include <bits/stdc++.h> using namespace std; using ll = long long; const int N = 2e3 + 10; int n, a[N]; unordered_map <int, int> mp; int main() { int _T; scanf("%d", &_T); while (_T--) { mp.clear(); scanf("%d", &n); for (int i = 1; i <= n; ++i) scanf("%d", a + i); ll res = 0; for (int i = n; i >= 1; --i) ++mp[a[i]]; for (int i = 1; i <= n; ++i) { --mp[a[i]]; for (int j = i - 1; j >= 1; --j) { int x = 2 * a[i] - a[j]; if (mp.count(x)) { res += mp[x]; } } } printf("%lld\n", res); } return 0; }