2019-2020 ACM-ICPC Brazil Subregional Programming Contest
Contents
Contest Info
Solved | A | B | C | D | E | F | G | H | I | J | K | L | M |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
11/13 | O | O | - | O | - | O | O | O | O | O | O | O | O |
- O 在比赛中通过
- Ø 赛后通过
- ! 尝试了但是失败了
- - 没有尝试
Solutions
A.Artwork
Solved By Hsueh- & ltslts. 0:33(+)
题意:
一个
思路:
并查集,将
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;
struct node {
int x, y, r;
void input() {
scanf("%d %d %d", &x, &y, &r);
}
} a[N];
int n, m, k;
int fa[N], sze[N];
int find(int x) {
return x == fa[x] ? fa[x] : fa[x] = find(fa[x]);
}
void merge(int x, int y) {
x = find(x), y = find(y);
if (x != y) {
if (sze[x] > sze[y])
swap(x, y);
fa[x] = y;
sze[y] += sze[x];
}
}
int sqr(int x) {
return x * x;
}
int main() {
scanf("%d %d %d", &n, &m, &k);
for (int i = 1; i <= k; ++i) {
a[i].input();
}
for (int i = 1; i <= k + 2; ++i) {
fa[i] = i, sze[i] = 1;
}
for (int i = 1; i <= k; ++i) {
if (a[i].x + a[i].r >= n || a[i].y <= a[i].r)
merge(i, k + 1);
if (a[i].x <= a[i].r || a[i].y + a[i].r >= m)
merge(i, k + 2);
}
for (int i = 1; i <= k; ++i) {
for (int j = 1; j < i; ++j) {
if (sqr(a[i].x - a[j].x) + sqr(a[i].y - a[j].y) <= sqr(a[i].r + a[j].r)) {
merge(i, j);
}
}
}
puts(find(k + 1) == find(k + 2) ? "N" : "S");
return 0;
}
B.Buffoon
Solved By Dup4. 0:07(+)
签到。
Code
C.Crossings With Danger
Solved By . 0:00(+)
题意:
思路:
D.Denouncing Mafia
Solved By Dup4 & Hsueh-. 1:39(+1)
题意:
给出一棵树,每次选择一个点,将该点到根的所有点都染色,现在可以选择
思路:
长链剖分,将每条链剖分出来,然后贪心取
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, K;
vector<vector<int>> G;
int fa[N], md[N], hson[N], deep[N], use[N];
void dfs(int u) {
hson[u] = 0;
for (auto &v : G[u]) {
deep[v] = deep[u] + 1;
dfs(v);
if (!hson[u] || md[v] > md[hson[u]])
hson[u] = v;
}
md[u] = md[hson[u]] + 1;
}
int main() {
scanf("%d%d", &n, &K);
G.resize(n + 1);
fa[1] = 1;
deep[1] = 0;
for (int i = 2; i <= n; ++i) {
scanf("%d", fa + i);
G[fa[i]].push_back(i);
}
int cnt = 0;
for (int i = 2; i <= n; ++i)
if (G[i].empty()) {
++cnt;
}
if (K >= cnt) {
printf("%d\n", n);
} else {
dfs(1);
vector<int> vec;
for (int i = 1; i <= n; ++i)
if (hson[i])
use[hson[i]] = 1;
for (int i = 1; i <= n; ++i)
if (use[i] == 0) {
vec.push_back(md[i]);
}
sort(vec.begin(), vec.end(), [&](int x, int y) {
return x > y;
});
int sum = 0;
for (int i = 0; i < K; ++i) sum += vec[i];
printf("%d\n", sum);
}
return 0;
}
E.Exhibition of Clownfish
Solved By . 0:00(+)
题意:
思路:
F.Forests in Danger
Solved By Dup4 & ltslts. 4:18(+)
题意:
给出若干条平行于坐标轴的线段和一个四条边都平行于坐标轴的矩形,然后给出一个
思路:
二分
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5 + 10;
int n, rate;
struct P {
int x, y;
void scan() {
scanf("%d%d", &x, &y);
}
};
struct node {
P s, e;
void scan() {
s.scan();
e.scan();
}
};
node li[N];
node Tri;
struct Hash {
int a[N], tot;
void init() {
tot = 0;
a[0] = 0;
}
void add(int x) {
a[++tot] = x;
}
void gao() {
sort(a + 1, a + 1 + tot);
tot = unique(a + 1, a + 1 + tot) - a - 1;
}
int get(int x) {
return lower_bound(a + 1, a + 1 + tot, x) - a;
}
} hx, hy;
struct SEG {
struct node {
int cnt, len;
void init() {
cnt = len = 0;
}
} t[N << 2];
void build(int id, int l, int r) {
t[id].init();
if (l == r)
return;
int mid = (l + r) >> 1;
build(id << 1, l, mid);
build(id << 1 | 1, mid + 1, r);
}
void up(int id, int l, int r) {
if (t[id].cnt > 0) {
t[id].len = hy.a[r] - hy.a[l - 1];
} else {
if (l == r)
t[id].len = 0;
else {
t[id].len = t[id << 1].len + t[id << 1 | 1].len;
}
}
}
void update(int id, int l, int r, int ql, int qr, int v) {
if (ql > qr)
return;
if (l >= ql && r <= qr) {
t[id].cnt += v;
up(id, l, r);
return;
}
int mid = (l + r) >> 1;
if (ql <= mid)
update(id << 1, l, mid, ql, qr, v);
if (qr > mid)
update(id << 1 | 1, mid + 1, r, ql, qr, v);
up(id, l, r);
}
} seg;
node rec[N];
vector<vector<P>> add, del;
ll calc(int r) {
hx.init();
hy.init();
for (int i = 1; i <= n; ++i) {
node tmp;
tmp.s.x = min(li[i].s.x, li[i].e.x) - r;
tmp.s.x = max(tmp.s.x, Tri.s.x);
tmp.s.y = min(li[i].s.y, li[i].e.y) - r;
tmp.s.y = max(tmp.s.y, Tri.s.y);
tmp.e.x = max(li[i].s.x, li[i].e.x) + r;
tmp.e.x = min(tmp.e.x, Tri.e.x);
tmp.e.y = max(li[i].s.y, li[i].e.y) + r;
tmp.e.y = min(tmp.e.y, Tri.e.y);
rec[i] = tmp;
hx.add(tmp.s.x);
hx.add(tmp.e.x);
hy.add(tmp.s.y);
hy.add(tmp.e.y);
}
hx.gao();
hy.gao();
for (int i = 1; i <= n; ++i) {
rec[i].s.x = hx.get(rec[i].s.x);
rec[i].e.x = hx.get(rec[i].e.x);
rec[i].s.y = hy.get(rec[i].s.y);
rec[i].e.y = hy.get(rec[i].e.y);
}
int cx = hx.tot, cy = hy.tot;
add.clear();
add.resize(cx + 5);
del.clear();
del.resize(cx + 5);
for (int i = 1; i <= n; ++i) {
add[rec[i].s.x].push_back({rec[i].s.y + 1, rec[i].e.y});
del[rec[i].e.x].push_back({rec[i].s.y + 1, rec[i].e.y});
}
seg.build(1, 1, cy);
ll res = 0;
for (int i = 1; i <= cx; ++i) {
res += 1ll * (hx.a[i] - hx.a[i - 1]) * seg.t[1].len;
for (auto &it : add[i]) {
seg.update(1, 1, cy, it.x, it.y, 1);
}
for (auto &it : del[i]) {
seg.update(1, 1, cy, it.x, it.y, -1);
}
}
return res * 100;
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
li[i].scan();
}
scanf("%d", &rate);
Tri.scan();
ll area = 1ll * (Tri.e.x - Tri.s.x) * (Tri.e.y - Tri.s.y) * rate;
int l = 0, r = 1e5, res = 1e5;
while (r - l >= 0) {
int mid = (l + r) >> 1;
if (calc(mid) >= area) {
r = mid - 1;
res = mid;
} else {
l = mid + 1;
}
}
printf("%d\n", res);
return 0;
}
G.Getting Confidence
Solved By Hsueh-. 1:00(+)
题意: -
思路:
- 取
转化为加法,跑费用流。
Code
#include <bits/stdc++.h>
using namespace std;
#define dbg(x...) \
do { \
cout << #x << " -> "; \
err(x); \
} while (0)
void err() {
cout << endl;
}
template <class T, class... Ts>
void err(const T& arg, const Ts&... args) {
cout << arg << ' ';
err(args...);
}
using db = double;
const int N = 2e4 + 10, M = 1e6 + 10, INF = 0x3f3f3f3f;
struct Edge {
int to, nxt, cap, flow;
db cost;
Edge() {}
Edge(int to, int nxt, int cap, int flow, db cost) : to(to), nxt(nxt), cap(cap), flow(flow), cost(cost) {}
} edge[M];
int head[N], tot;
int pre[N];
db dis[N];
bool vis[N];
void Init() {
tot = 0;
memset(head, -1, sizeof head);
}
void addedge(int u, int v, int cap, db cost) {
edge[tot] = Edge(v, head[u], cap, 0, cost);
head[u] = tot++;
edge[tot] = Edge(u, head[v], 0, 0, -cost);
head[v] = tot++;
}
bool SPFA(int S, int T) {
queue<int> q;
for (int i = 0; i < N; ++i) {
dis[i] = INF;
vis[i] = false;
pre[i] = -1;
}
dis[S] = 0;
vis[S] = true;
q.push(S);
while (!q.empty()) {
int u = q.front();
q.pop();
// dbg(u);
vis[u] = false;
for (int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].to;
if (edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost) {
dis[v] = dis[u] + edge[i].cost;
pre[v] = i;
if (!vis[v]) {
q.push(v);
vis[v] = true;
}
}
}
}
// for (int i = 1; i <= 11; ++i) {
// dbg(i, pre[i]);
// }
if (pre[T] == -1)
return false;
else
return true;
}
int minCostMaxflow(int s, int t, db& cost) {
int flow = 0;
cost = 0;
while (SPFA(s, t)) {
int Min = INF;
for (int i = pre[t]; ~i; i = pre[edge[i ^ 1].to]) {
Min = min(Min, edge[i].cap - edge[i].flow);
}
for (int i = pre[t]; ~i; i = pre[edge[i ^ 1].to]) {
edge[i].flow += Min;
edge[i ^ 1].flow -= Min;
cost += edge[i].cost * Min;
}
flow += Min;
}
return flow;
}
int n;
int res[N];
int main() {
scanf("%d", &n);
Init();
int S = 2 * n + 1, T = 2 * n + 2;
for (int i = 1; i <= n; ++i) {
addedge(S, i, 1, 0);
addedge(i + n, T, 1, 0);
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
db x = 0;
scanf("%lf", &x);
x = log(x);
addedge(i, j + n, 1, -x);
}
}
db cost;
minCostMaxflow(S, T, cost);
for (int u = 1; u <= n; ++u) {
for (int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].to;
if (v != S && edge[i].cap == edge[i].flow) {
res[v - n] = u;
}
}
}
for (int i = 1; i <= n; ++i) {
printf("%d%c", res[i], " \n"[i == n]);
}
return 0;
}
H.Hour for a Run
Solved By Hsueh-. 0:06(+)
题意:
操场一圈有
思路:
签到。
Code
I.Interplanetary
Solved By Hsueh-. 3:34(+)
题意:
思路:
离线后动态加点跑 Floyd。
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 4e2 + 10, M = 1e5 + 10, INF = 0x3f3f3f3f;
#define dbg(x...) \
do { \
cout << #x << " -> "; \
err(x); \
} while (0)
void err() {
cout << endl;
}
template <class T, class... Ts>
void err(const T& arg, const Ts&... args) {
cout << arg << ' ';
err(args...);
}
struct E {
int a, b, x, id, op;
E() {}
E(int a, int b, int x, int id, int op) : a(a), b(b), x(x), id(id), op(op) {}
bool operator<(const E& other) const {
return x < other.x;
}
};
struct node {
int id, x;
node() {}
node(int id, int x) : id(id), x(x) {}
bool operator<(const node& other) const {
return x < other.x;
}
};
int n, m, top;
int temp[N], res[M];
int G[N][N], _G[N][N];
int id[N];
vector<E> Q;
vector<node> vec;
void gao() {
// T = 0 <= x
for (int i = 1; i <= n; ++i) {
vec.push_back(node(i, temp[i]));
}
sort(vec.begin(), vec.end());
sort(Q.begin(), Q.end());
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
G[i][j] = _G[i][j];
}
}
int pos = -1;
for (auto it : Q) {
while (pos < n - 1 && vec[pos + 1].x <= id[it.x]) {
// dbg(pos);
pos++;
int k = vec[pos].id;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
G[i][j] = min(G[i][j], G[i][k] + G[k][j]);
}
}
}
if (it.op == 0)
res[it.id] = G[it.a][it.b];
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
G[i][j] = _G[i][j];
}
}
// T = 1 >= x
reverse(vec.begin(), vec.end());
reverse(id + 1, id + 1 + top);
pos = -1;
for (auto it : Q) {
// dbg(it.id);
while (pos < n - 1 && vec[pos + 1].x >= id[it.x]) {
pos++;
int k = vec[pos].id;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
G[i][j] = min(G[i][j], G[i][k] + G[k][j]);
}
}
}
if (it.op == 1)
res[it.id] = G[it.a][it.b];
}
}
int main() {
scanf("%d %d", &n, &m);
memset(_G, INF, sizeof _G);
for (int i = 1; i <= n; ++i) {
_G[i][i] = 0;
}
set<int> se;
for (int i = 1; i <= n; ++i) {
scanf("%d", temp + i);
se.insert(temp[i]);
}
for (auto it : se) {
id[++top] = it;
}
for (int i = 1, u, v, w; i <= m; ++i) {
scanf("%d %d %d", &u, &v, &w);
_G[u][v] = _G[v][u] = w;
}
int q;
scanf("%d", &q);
for (int i = 1, a, b, x, t; i <= q; ++i) {
scanf("%d %d %d %d", &a, &b, &x, &t);
if (x > top)
x = top;
Q.push_back(E(a, b, x, i, t));
}
gao();
for (int i = 1; i <= q; ++i) {
if (res[i] == INF) {
res[i] = -1;
}
printf("%d\n", res[i]);
}
return 0;
}
J.Jar of Water Game
Solved By Hsueh-. 2:02(+1)
题意:
一个游戏,总共有 A23456789DJQK
和 wildcard
,
规则如下:
个人坐成一圈,第 个人先开始。 - 每个人给自己的下一位,也就是
给 。 - 如果刚拿到
wildcard
则不能将wildcard
给下一家,否则一定给wildcard
。 - 否则找到数量最小的给下一家。
- 如果有多个数量最小的则拿出数字最下的。
- 如果一个人手上四张牌都一样则获胜。
思路:
模拟
Code
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
int get(char c) {
if (c == 'A')
return 1;
else if (c == 'D')
return 10;
else if (c == 'Q')
return 11;
else if (c == 'J')
return 12;
else if (c == 'K')
return 13;
else
return c - '0';
}
struct E {
bool First, wildcard;
vector<int> card;
int get() {
if (wildcard) {
if (First) {
First = false;
} else {
wildcard = false;
return -1;
}
}
map<int, int> mp;
for (auto it : card) {
mp[it]++;
}
int Min = INF;
for (auto it : mp) {
Min = min(it.second, Min);
}
for (auto it : mp) {
if (it.second == Min) {
card.erase(find(card.begin(), card.end(), it.first));
return it.first;
}
}
}
void insert(int x) {
if (x == -1) {
First = wildcard = true;
} else {
card.push_back(x);
}
}
} a[30];
bool win(int x) {
if (a[x].wildcard)
return false;
if (a[x].card[0] != a[x].card[1])
return false;
if (a[x].card[1] != a[x].card[2])
return false;
if (a[x].card[2] != a[x].card[3])
return false;
return true;
}
int n, k;
int main() {
scanf("%d %d", &n, &k);
for (int i = 1; i <= n; ++i) {
char s[10];
scanf("%s", s + 1);
a[i].card.clear();
for (int j = 1; j <= 4; ++j) {
a[i].insert(get(s[j]));
}
a[i].First = a[i].wildcard = false;
}
a[k].First = a[k].wildcard = true;
for (int i = 1; i <= n; ++i) {
if (win(i)) {
printf("%d\n", i);
return 0;
}
}
int cur = k;
while (true) {
int nxt = cur % n + 1;
a[nxt].insert(a[cur].get());
if (win(cur))
break;
cur = nxt;
}
printf("%d\n", cur);
return 0;
}
K.Keep Calm and Sell Balloons
Solved By Dup4 & ltslts. 3:14(+)
题意:
- 给出
的矩阵,矩阵上的数字从左往右,从上到下,依次为 。 - 现在可以任选一个起点出发,每次可以上下左右对角线八个方向走到相邻的并且没有被访问过的点走,问访问完所有点的方案数。
思路:
令
那么我们考虑怎么递推
- 从
出发,如果最终回到 ,那么每次往右可以选择走上边或者往下边,那么回来回到 的路径是固定的,这部分贡献是 - 如果第二步走
,那么第三步可以走 或者 ,容易发现这是一个子问题,方案数为 。 - 再考虑第三步走
,那么走法是 或者 ,然后就是一个 规模的子问题,贡献是 。
所以有:
那么四个角的贡献就是
容易发现,我们发现从第一层的第
- 显然,它不可能在第二步走到
。 - 假设它往右走,方案数为
,然后回到 这个位置,再往左边走,这部分的方案是 ,所以往右走的贡献是 。 - 同理可得,往左边走的方案数为
。
那么答案就是:
令
令
容易发现
Code
#include <bits/stdc++.h>
using ll = long long;
using namespace std;
const int mod = 1e9 + 7;
int n;
inline void chadd(ll &x, ll y) {
x += y;
while (x >= mod) x -= mod;
while (x < 0) x += mod;
}
struct node {
ll a[4][4];
node() {}
ll *operator[](int x) {
return a[x];
}
void init() {
memset(a, 0, sizeof a);
}
node operator*(const node &other) const {
node res = node();
res.init();
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
for (int k = 0; k < 4; ++k) {
chadd(res.a[i][j], a[i][k] * other.a[k][j] % mod);
}
}
}
return res;
}
};
node qpow(node base, node res, ll n) {
while (n) {
if (n & 1)
res = res * base;
base = base * base;
n >>= 1;
}
return res;
}
ll gao() {
if (n == 1)
return 2;
if (n == 2)
return 24;
node base = node();
base.init();
base[0][0] = 6, base[0][1] = 1, base[0][2] = 0, base[0][3] = 4;
node res = node();
res.init();
res[0][0] = 2, res[0][1] = 1;
res[1][0] = 4, res[1][2] = 2;
res[2][2] = 2;
res[3][0] = 1, res[3][3] = 2;
swap(res, base);
res = qpow(base, res, n - 2);
return 4ll * (res[0][0] + 2ll * res[0][2] % mod) % mod;
}
int main() {
scanf("%d", &n);
ll res = gao();
res = (res % mod + mod) % mod;
printf("%lld\n", res);
return 0;
}
L.Less Coin Tosses
Solved By Dup4 & ltslts. 1:07(+)
题意:
有一个硬币,它不是公平的,即掷出正面和反面的概率不同。
现在为了公平,有如下策略:
- 选一个
。 - 那么有
个 01串
,Alice 拿一部分,Bob 拿一部分,剩下的舍弃,然后将该硬币投掷次,根据掷出的正反面形成一个长度为 的 01串
,如果该串在 Alice 那部分中,Alice 获胜,如果在 Bob 那部分中,Bob 获胜,否则再来一次。
现在给定 01串
,使得该玩法是公平的。
思路:
我们假设投出正面的概率为 01串
的概率为
那么可以根据 01串
进行分类,同类的均分给两人,那么容易发现,如果某类字符串是奇数个,那么必然要留下一个。
所以答案就是
Code
M.Maratona Brasileira de Popcorn
Solved By Dup4. 0:33(+)
题意:
有
现在有两个限制条件:
- 每个人只能吃一段袋子标号连续的爆米花
- 同一袋里的爆米花只能被同一个人吃
问最少需要多少时间,使得爆米花能被吃完。
思路:
二分时间,贪心 check。
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, m, T, a[N];
int calc(int x) {
int tot = x * T;
int res = 1, sum = 0;
for (int i = 1; i <= n; ++i) {
if (a[i] > tot)
return 1e9;
if (a[i] + sum <= tot) {
sum += a[i];
} else {
sum = a[i];
++res;
}
}
return res;
}
int main() {
scanf("%d%d%d", &n, &m, &T);
for (int i = 1; i <= n; ++i) scanf("%d", a + i);
int l = 1, r = 1e9 / T + 5, res = 1e9;
while (r - l >= 0) {
int mid = (l + r) >> 1;
if (calc(mid) <= m) {
r = mid - 1;
res = mid;
} else {
l = mid + 1;
}
}
printf("%d\n", res);
return 0;
}
Created: March 27, 2022