Codeforces Round #583 (Div. 1 + Div. 2, based on Olympiad of Metropolises)
Posted hankeke
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #583 (Div. 1 + Div. 2, based on Olympiad of Metropolises)相关的知识,希望对你有一定的参考价值。
这一场非常的惨啊。
D 题因为一个sb的错误调了一个半小时。然后 E 题根本没有看。
难受。
调回了蓝名。
A. Optimal Currency Exchange
dollar 可以随便选,euro 必须是 (5) 的倍数。可以把 (e) 变成 (5e) 做。
然后我就很愉快地写了个 (min(n mod d mod e, n mod e mod d)) 交了上去。
然后 Wrong answer on pretest 7
???
哦想了想好吧,可以枚举 (d) 选了多少个。复杂度 (O(n/d))???
看上去复杂度不太靠谱。(其实很靠谱,是我sb了
于是可以小凯的疑惑一波,大于 (frac{de}{gcd(d,e)} - d - e) 直接对 (gcd(d,e)) 取模。于是这样的复杂度就变成了很靠谱的了。
好吧,我现在已经沦落到连 div2 的 A 题都不会了。
#include<bits/stdc++.h>
#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back
template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;}
typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
template<typename I>
inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
}
const int N = 100 * 100 * 5 + 7;
int n, d, e;
int a[N];
inline void work() {
e = 5 * e;
int hkk = std::__gcd(d, e);
if (n / hkk > ((d / hkk) * (e / hkk) - (d / hkk) - (e / hkk))) {
printf("%d
", n % hkk);
return;
}
for (int i = 0; i <= e && i * d <= n; ++i)
for (int j = 0; j <= d && i * d + j * e <= n; ++j) a[i * d + j * e] = 1;
int ans = 0;
while (!a[n]) ++ans, --n;
printf("%d
", ans);
}
inline void init() {
read(n), read(d), read(e);
}
int main() {
#ifdef hzhkk
// freopen("hkk.in", "r", stdin);
#endif
init();
work();
fclose(stdin), fclose(stdout);
return 0;
}
B. Badges
这题不用说吧。
#include<bits/stdc++.h>
#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back
template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;}
typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
template<typename I>
inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
}
int n, b, g;
inline void work() {
printf("%d
", std::min(n, b) - std::max(0, n - g) + 1);
}
inline void init() {
read(b), read(g), read(n);
}
int main() {
#ifdef hzhkk
// freopen("hkk.in", "r", stdin);
#endif
init();
work();
fclose(stdin), fclose(stdout);
return 0;
}
C. Bad Sequence
如果可以通过移动一次解决问题,那么出问题的一定是右括号。所以只需要统计有多少右括号不匹配的。最后应该是不匹配的左括号-不匹配的右括号=0。
#include<bits/stdc++.h>
#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back
template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;}
typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
template<typename I>
inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
}
const int N = 2e5 + 7;
int n;
char s[N];
inline void work() {
int cnt = 0, pri = 1, cc = 0;
for (int i = 1; i <= n; ++i) {
if (s[i] == ')') {
if (!cnt) ++cc;
else --cnt;
} else ++cnt;
}
if (cc > 1 || cnt - cc) {
puts("No");
return;
}
puts("Yes");
}
inline void init() {
read(n);
scanf("%s", s + 1);
}
int main() {
#ifdef hzhkk
// freopen("hkk.in", "r", stdin);
#endif
init();
work();
fclose(stdin), fclose(stdout);
return 0;
}
D. Treasure Island
答案只有可能是 (0, 1, 2)。
(0) 的话就是从起点到不了终点。
主要问题是 (1) 和 (2) 怎么区分。
如果整个图上堵了一个点以后起点就到不了终点了,那就是 (1)。
一开始以为只要有一个割点就可以了。但是这个是有向图。但是是一个 DAG。
于是就写起了支配树。后来发现需要去掉从起点根本到不了的点。
然后就一直 TLE on test 16。一直调到结束。
一直到可以看数据了才发现 dfs 判断从起点可以到哪些点的时候忘了去掉已经走过的点了。
这个错误我也能犯!!!
后面的题目也没有看。
其实这个题还有一种更方便的方法。能堵掉一个点就不连通说明,从起点到终点的所有路径中,存在一个到起点的距离上的点都是同一点。所以直接求一下每个点是不是在起点到终点的路径上(即能到起点能到它,它也能到终点)。
只写了第一种。
#include<bits/stdc++.h>
#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back
template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;}
typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
template<typename I>
inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
}
const int N = 1e6 + 7;
const int LOG = 3;
int n, m;
char s[2][N], vis[N];
int ans = 2;
int deg[N], f[N][LOG], dep[N], q[N];
struct Edge { int to, ne; } g[N << 2]; int head[N], tot;
inline void addedge(int x, int y) { g[++tot].to = y, g[tot].ne = head[x], head[x] = tot; }
inline void adde(int x, int y) { addedge(x, y), addedge(y, x); }
inline int id(int x, int y) { return (x - 1) * m + y; }
inline int LCA(int x, int y) {
// dbg("+++++++++++++++++ x = %d, y = %d
", x, y);
if (!x || !y) return x ^ y;
if (dep[x] < dep[y]) std::swap(x, y);
for (int i = LOG - 1; i >= 0; --i) if (dep[f[x][i]] >= dep[y]) x = f[x][i];
if (x == y) return x;
// dbg("----------------- x = %d, y = %d
", x, y);
for (int i = LOG - 1; i >= 0; --i) if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
return f[x][0];
}
inline void dfs(int x) {
vis[x] = 1;
for fec(i, x, y) if (!vis[y]) dfs(y);
}
inline void topsort() {
int hd = 0, tl = 0;
for (int i = 1; i <= 1; ++i) if (!deg[i]) q[++tl] = i, f[i][0] = n * m + 1;
while (hd < tl) {
int x = q[++hd];
if (x > 1 && f[x][0] != 1 && f[f[x][0]][0] != 1) f[x][0] = f[f[x][0]][0];
dep[x] = dep[f[x][0]] + 1;
// dbg("x = %d, f[x][0] = %d
", x, f[x][0]);
// dbg("x = %d
", dep[x]);
for (int i = 1; i < LOG; ++i) f[x][i] = f[f[x][i - 1]][i - 1];
for fec(i, x, y) {
if (!--deg[y]) q[++tl] = y;
f[y][0] = LCA(f[y][0], x);
// dbg("********* %d %d %d
", x, y, deg[y]);
}
}
}
inline void work() {
dfs(1);
for (int i = 1; i <= n * m; ++i)
if (vis[i])
for fec(j, i, y) ++deg[y];
topsort();
if (!vis[n * m]) puts("0");
else if (f[n * m][0] != 1) puts("1");//, dbg("*** %d
", f[n * m][0]);
else puts("2");
}
inline void init() {
read(n), read(m);
int now = 0, pre = 1;
for (int i = 1; i <= n; ++i) {
std::swap(now, pre);
scanf("%s", s[now] + 1);
for (int j = 1; j <= m; ++j) {
if (j > 1 && s[now][j - 1] == '.' && s[now][j] == '.') addedge(id(i, j - 1), id(i, j));
if (i > 1 && s[pre][j] == '.' && s[now][j] == '.') addedge(id(i - 1, j), id(i, j));
}
}
}
int main() {
#ifdef hzhkk
freopen("hkk.in", "r", stdin);
#endif
init();
work();
fclose(stdin), fclose(stdout);
return 0;
}
E. Petya and Construction Set
一个直观的想法是先拿出一部分点构造一条链,然后在上面追加点。
如果点 (2i-1) 位于链的 (x) 位,那么我们就要在链的第 (x+d_i-1)个点后面加上点 (2i) 就可以了。
但是要保证第 (x+d_i-1) 个点存在啊。
不妨假设第 (x-1) 位上是 (2j-1),这个点已经成功对接了。因为新加一个点最好情况下会给链加上一个点,那么有 (x-1+d_j leq len),其中 (len) 为加上 (2j-1) 以后的链最长的长度。
发现只要我们能够保证 (x+d_i-1leq x-1+d_j) 就可以了。也就是 (d_i leq d_j)。这完全是可以实现的。
所以把 (d) 数组从大到小排序,然后按上面说的来处理就可以了。
#include<bits/stdc++.h>
#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back
template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;}
typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
template<typename I>
inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
}
const int N = 1e5 + 7;
int n;
int b[N], s[N], id[N << 1], pre[N << 1];
struct wph {
int d, id;
} a[N];
inline void add(int x, int fa, int tag = 1) {
if (tag) s[x] = s[fa] + 1, b[s[x]] = x;
printf("%d %d
", x, fa);
}
inline void work() {
std::sort(a + 1, a + n + 1, [](const wph &a, const wph &b) {
return a.d > b.d;
});
for (int i = 1; i < n; ++i) printf("%d %d
", a[i].id * 2 - 1, a[i + 1].id * 2 - 1);
for (int i = 1; i <= n; ++i) id[i] = a[i].id * 2 - 1;
int nn = n;
for (int i = 1; i <= n; ++i)
if (i + a[i].d - 1 < nn) printf("%d %d
", id[i] + 1, id[i + a[i].d - 1]);
else id[++nn] = id[i] + 1, printf("%d %d
", id[nn], id[nn - 1]);
}
inline void init() {
read(n);
for (int i = 1; i <= n; ++i) read(a[i].d), a[i].id = i;
}
int main() {
#ifdef hzhkk
// freopen("hkk.in", "r", stdin);
#endif
init();
work();
fclose(stdin), fclose(stdout);
return 0;
}
F. Employment
挺好的题。
一直显然的贪心是把 (a) 和 (b) 分别排序,然后对应位算距离就可以了。
但是由于这是一个环,所以不知道到底哪一位对应哪一位。
所以可以枚举 (a_1) 和 (b_i) 对应。(O(n^2))。
写了一个这样的暴力,发现是对的。
然后就不会了,题解里面是这样说的:
对于两个坐标 (x, y),他们的距离只有可能是这四种情况。
- (y + n - xquad|quad 0 leq y < x - frac n2);
- (x - yquad | quad x - frac n2 leq y < x);
- (y - x quad | quad x leq y leq x + frac n2);
- (x + n - y quad | quad x + frac n2 < y leq n)。
就只看了这么一点,所以貌似最后写出了都东西和大部分人不太一样。
然后发现对于每一个 (a_i),在枚举对应的 (b_j) 时,上面四种情况都是连续的 (b_j)。于是枚举坐标差,直接在有情况改变的坐标差处处理一下就可以了。
代码实现非常复杂,细节很多。(仅限于上面的做法
(貌似大部分人写的和这个不一样,没有去学习
#include<bits/stdc++.h>
#define fec(i, x, y) (int i = head[x], y = g[i].to; i; i = g[i].ne, y = g[i].to)
#define dbg(...) fprintf(stderr, __VA_ARGS__)
#define File(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define fi first
#define se second
#define pb push_back
template<typename A, typename B> inline char smax(A &a, const B &b) {return a < b ? a = b , 1 : 0;}
template<typename A, typename B> inline char smin(A &a, const B &b) {return b < a ? a = b , 1 : 0;}
typedef long long ll; typedef unsigned long long ull; typedef std::pair<int, int> pii;
template<typename I>
inline void read(I &x) {
int f = 0, c;
while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0;
x = c & 15;
while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15);
f ? x = -x : 0;
}
const int N = 2e5 + 7;
int n, m;
int aa[N], sta[N], a[N], b[N], sta2[N];
pii sa[N], sb[N];
std::vector<pii> v[N], v2[N];
inline int dis(int x, int y) {
if (x > y) std::swap(x, y);
return std::min(y - x, x + n - y);
}
/*
inline void work() {
std::sort(a + 1, a + m + 1);
std::sort(b + 1, b + m + 1);
ll ans = 0x7fffffffffffffff, pos;
for (int i = 1; i <= m; ++i) {
ll cnt = 0;
for (int j = 1; j <= m; ++j) cnt += dis(a[j].fi, b[(i + j - 2) % m + 1].fi);
smin(ans, cnt) && (pos = i);
}
dbg("pos = %d
", pos);
for (int i = 1; i <= m; ++i) aa[a[i].se] = b[(i + pos - 2) % m + 1].se;
printf("%I64d
", ans);
for (int i = 1; i <= m; ++i) printf("%d%c", aa[i], "
"[i == n]);
}*/ // That's force;
inline int ff(int x) { return std::upper_bound(b + 1, b + m + 1, x) - b - 1; }
inline int f2(int x) { return std::lower_bound(a + 1, a + m + 1, x) - a; }
inline void work() {
std::sort(sa + 1, sa + m + 1);
std::sort(sb + 1, sb + m + 1);
for (int i = 1; i <= m; ++i) a[i] = sa[i].fi, b[i] = sb[i].fi;
int n2 = n / 2;
for (int i = 1; i <= m; ++i) {
int p1 = a[i] - n2 - 1, p2 = a[i] - 1, p3 = a[i] + n / 2, p4 = n;
// dbg("i = %d, p1 = %d, p2 = %d, p3 = %d, p4 = %d
", i, p1, p2, p3, p4);
p1 = ff(p1) % m, p2 = ff(p2) % m, p3 = ff(p3) % m, p4 = ff(p4) % m;
// dbg("i = %d, p1 = %d, p2 = %d, p3 = %d, p4 = %d
", i, p1, p2, p3, p4);
if (p1 != p2) v[(p1 - i + 1 + m) % m].pb(pii(i, 1));
if (p2 != p3) v[(p2 - i + 1 + m) % m].pb(pii(i, 2));
if (p3 != p4) v[(p3 - i + 1 + m) % m].pb(pii(i, 3));
if (p4 != p1) v[(p4 - i + 1 + m) % m].pb(pii(i, 0));
}
for (int i = 1; i <= m; ++i) {
int p1 = b[i] - n2, p2 = b[i] + 1, p3 = b[i] + n / 2 + 1, p4 = 1;
// dbg("i = %d, p1 = %d, p2 = %d, p3 = %d, p4 = %d
", i, p1, p2, p3, p4);
p1 = f2(p1) % m, p2 = f2(p2) % m, p3 = f2(p3) % m, p4 = f2(p4) % m;
// dbg("i = %d, p1 = %d, p2 = %d, p3 = %d, p4 = %d
", i, p1, p2, p3, p4);
if (p1 != p4) v2[(-p1 + i + 1 + m) % m].pb(pii(i, 3));
if (p2 != p1) v2[(-p2 + i + 1 + m) % m].pb(pii(i, 2));
if (p3 != p2) v2[(-p3 + i + 1 + m) % m].pb(pii(i, 1));//, i == 3 && dbg("********** %d
", (-p3 + i + 1 + m) % m);
if (p4 != p3) v2[(-p4 + i + 1 + m) % m].pb(pii(i, 0));
}
ll sum_a[4] = {0}, sum_b[4] = {0}, pos, cnt[4] = {0}, cnt2[4] = {0};
ll ans = 0x7fffffffffffffff;
memset(sta, -1, sizeof(sta));
// for (int i = 0; i < 4; ++i) for (pii j : v[i]) sum_a[j.se] += a[j.fi], sum_b[j.se] += b[j.fi], ++cnt[j.se], sta[j.fi] = j.se;
for (int i = 1; i <= m; ++i) {
int x = i, y;
if (b[i] < a[i] - n2) y = 0;
else if (b[i] < a[i]) y = 1;
else if (b[i] <= a[i] + n2) y = 2;
else y = 3;
// dbg("******************** %d %d
", x, y);
sum_a[y] += a[x], sum_b[y] += b[x], cnt[y] += 1, cnt2[y] += 1;
sta[x] = y, sta2[x] = y;
}
for (int i = 1; i <= m; ++i) {
// dbg("i = %d,
", i);
// for (int j = 0; j < 4; ++j) dbg("sum_a[%d] = %lld, sum_b = %lld, cnt = %lld, cnt2 = %lld, %lld
", j, sum_a[j], sum_b[j], cnt[j], cnt2[j], sum_b[0] + n * cnt[0] - sum_a[0] + sum_a[1] - sum_b[1] + sum_b[2] - sum_a[2] + sum_a[3] + n * cnt[3] - sum_b[3]);
if (i) smin(ans, sum_b[0] + n * cnt[0] - sum_a[0] + sum_a[1] - sum_b[1] + sum_b[2] - sum_a[2] + sum_a[3] + n * cnt[3] - sum_b[3]) && (pos = i);
if (cnt[0] != cnt2[0] || cnt[1] != cnt2[1] || cnt[2] != cnt2[2] || cnt[3] != cnt2[3]) {
//// printf("(%I64d, %I64d, %I64d, %I64d, %I64d, %I64d, %I64d, %I64d)
", cnt[0], cnt2[0], cnt[1], cnt2[1], cnt[2], cnt2[2], cnt[3], cnt2[3]);
// int dd = sum_b[3];
// int x = std::lower_bound(b + 1, b + n + 1, dd) - b;
// printf("**** x = %d, i = %d, %d %d
", x, i, dd, a[(x - i + 1 + m - 1) % m + 1]);
// printf("***************** %d %d
", a[m], b[m]);{
// int i = m;
// int p1 = a[i] - n2 - 1, p2 = a[i] - 1, p3 = a[i] + n / 2, p4 = n;
// // dbg("i = %d, p1 = %d, p2 = %d, p3 = %d, p4 = %d
", i, p1, p2, p3, p4);
// p1 = ff(p1) % m, p2 = ff(p2) % m, p3 = ff(p3) % m, p4 = ff(p4) % m;
// dbg("i = %d, p1 = %d, p2 = %d, p3 = %d, p4 = %d
", i, p1, p2, p3, p4);
// if (p1 != p2) v[(p1 - i + 1 + m) % m].pb(pii(i, 1));
// if (p2 != p3) v[(p2 - i + 1 + m) % m].pb(pii(i, 2));
// if (p3 != p4) v[(p3 - i + 1 + m) % m].pb(pii(i, 3));
// if (p4 != p1) v[(p4 - i + 1 + m) % m].pb(pii(i, 0));
// }
return;
}
for (pii j : v[i]) {
int x = j.fi, &y = sta[x];
// dbg("v1 : i = %d, x = %d, sta[x] = %d, y = %d
", i, x, sta[x], j.se);
if (~y) sum_a[y] -= a[x], cnt[y] -= 1;
y = j.se;
sum_a[y] += a[x], cnt[y] += 1;
}
for (pii j : v2[i]) {
int x = j.fi, &y = sta2[x];
// dbg("v2 : i = %d, x = %d, sta[x] = %d, y = %d
", i, x, sta2[x], j.se);
if (~y) sum_b[y] -= b[x], cnt2[y] -= 1;
y = j.se;
sum_b[y] += b[x], cnt2[y] += 1;
}
// dbg("ans = %lld
", ans);
}
printf("%I64d
", ans);
for (int i = 1; i <= m; ++i) aa[sa[i].se] = sb[(i + pos - 2) % m + 1].se;
for (int i = 1; i <= m; ++i) printf("%d%c", aa[i], "
"[i == n]);
}
inline void init() {
read(n), read(m);
for (int i = 1; i <= m; ++i) read(sa[i].fi), sa[i].se = i;
for (int i = 1; i <= m; ++i) read(sb[i].fi), sb[i].se = i;
}
int main() {
#ifdef hzhkk
freopen("hkk.in", "r", stdin);
#endif
init();
work();
fclose(stdin), fclose(stdout);
return 0;
}
以上是关于Codeforces Round #583 (Div. 1 + Div. 2, based on Olympiad of Metropolises)的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #583 (Div. 1 + Div. 2, based on Olympiad of Metropolises), problem: (D) Treasure Is
Codeforces Round #436 E. Fire(背包dp+输出路径)
[ACM]Codeforces Round #534 (Div. 2)
codeforces #583 problem D(搜索好题)