Contest Info
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
", 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
", 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
%d
", 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
1");
} 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( ext{段数}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
", 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
", x, y, res);
}
return 0;
}
Problem J. Just the Last Digit
题意:
有一个(n)个点的有向图,(i) 到 (j)有边,那么必然有(i < j)。
现在给出(a_{i, j} = i
ightarrow j)的路径条数模(10)的结果,要你还原这个图。
思路:
正着推,考虑新加入一个点(k)的时候,我们枚举一个点(i(i < k)),如果(i)到(k)通过点(j(i < j < k))中转的路径之和模(10)不等于(a_{i, j}),那么(i
ightarrow 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 << "