Educational Codeforces Round 4 复盘
A
读完题总是会楞一下,然后才开始写。
一遍 AC。
const int MAXN = 100 + 10;
int n, p, q;
char ss[MAXN];
int main() {
scanf("%d %d %d", &n, &p, &q);
scanf("%s", ss);
for (int ps = 0; ps <= n; ++ps) {
if ((n - ps * p) < 0) break;
if ((n - ps * p) % q) continue;
int qs = (n - ps * p) / q;
printf("%d", ps + qs);
for (int i = 0; i < ps * p; ++i) {
if (i % p == 0) puts("");
putchar(ss[i]);
}
for (int i = ps * p; i < n; ++i) {
if ((i - ps * p) % q == 0) puts("");
putchar(ss[i]);
}
return 0;
}
puts("-1");
return 0;
}
B
读题就读了好几分钟。读懂了就很好写了。
一遍 AC。
const int MAXN = 2e5 + 10;
int pos[MAXN];
int n;
int main() {
n = read();
rep (i, 1, n) pos[read()] = i;
lli ans = 0;
rep (i, 1, n - 1) ans += std::abs(pos[i] - pos[i + 1]);
printf("%lld\n", ans);
return 0;
}
C
第一发忘了判断栈是否为空,然后 WA on 10
const int MAXN = 1e6 + 10;
int n;
char ss[MAXN];
std::stack<char> stk;
int main() {
scanf("%s", ss + 1);
int ans = 0;
n = (int) strlen(ss + 1);
rep (i, 1, n) {
if (ss[i] == '<' || ss[i] == '{' || ss[i] == '[' || ss[i] == '(') {
stk.push(ss[i]);
} else {
if (stk.empty()) {
puts("Impossible");
return 0;
}
switch (ss[i]) {
case '>':
ans += (stk.top() != '<');
break;
case '}':
ans += (stk.top() != '{');
break;
case ']':
ans += (stk.top() != '[');
break;
case ')':
ans += (stk.top() != '(');
break;
}
stk.pop();
}
}
if (stk.empty()) printf("%d\n", ans);
else puts("Impossible");
return 0;
}
D. The Union of k-Segments
类似于之前 ABC 某题的思路,先离散化,然后差分,统计答案的时候用原数组的值。
但是这么做只能处理整数端点,对于 \([1, 2] + [3, 4]\) 这种是没法处理的,所以考虑把端点都 \(\times 2\),然后在离散化数组里加入 \(2l - 1, 2l, 2r, 2r + 1\) 四个值,这样就能很方便处理了。
然后调了一场没调出来,赛后才发现自己访问原数组的时候脑抽了,std::vector
从 0 开始储存结果少减了一个 1.
#易错警示:分清 0-indexed 和 1-indexed 的区别。
const int MAXN = 1e6 + 10;
int n, k;
int tl[MAXN], tr[MAXN];
std::vector<int> lisan;
int diff[MAXN << 2];
int main() {
n = read(); k = read();
rep (i, 1, n) {
int u = read(); int v = read();
tl[i] = u, tr[i] = v;
lisan.push_back(u * 2 - 1);
lisan.push_back(u * 2);
lisan.push_back(v * 2);
lisan.push_back(v * 2 + 1);
}
std::sort(ALL(lisan));
auto it = std::unique(ALL(lisan));
if (it != lisan.end()) lisan.erase(it, lisan.end());
rep (i, 1, n) {
int fl = (int) (std::lower_bound(ALL(lisan), tl[i] * 2) - lisan.begin() + 1);
int fr = (int) (std::lower_bound(ALL(lisan), tr[i] * 2) - lisan.begin() + 1);
// DEBUG(fl); DEBUG(fr);
++diff[fl]; --diff[fr + 1];
}
rep (i, 1, (int) lisan.size() + 1) diff[i] += diff[i - 1];
// rep (i, 1, (int) lisan.size() + 1) printf("%d ", diff[i]);
int tl = 0;
std::vector<std::pair<int, int> > anss;
lisan.push_back(0);
rep (i, 1, (int) lisan.size() - 1) {
if (diff[i] < k) {
if (tl) {
anss.push_back({lisan[tl - 1] / 2, (lisan[i - 2]) / 2});
tl = 0;
}
} else {
if (!tl) tl = i;
}
}
printf("%d\n", (int) anss.size());
for (auto v : anss) {
printf("%d %d\n", v.fi, v.se);
}
return 0;
}
或者有更简单的做法,你甚至不需要一个完整的 diff
数组,只需要把左端点看成一个 +1 的事件,右端点看成一个 -1 的事件,然后排个序按上面的过程扫一遍就可以了。
const int MAXN = 1e6 + 10;
int n, k;
struct Seg { int l, x; }; std::vector<Seg> events;
bool operator < (const Seg &x, const Seg &y) { return x.l == y.l ? x.x > y.x : x.l < y.l; }
int main() {
n = read(); k = read();
rep (i, 1, n) {
int l = read(); int r = read();
events.push_back({l * 2 - 1, 0});
events.push_back({l * 2, 1});
events.push_back({r * 2 + 1, -1});
} std::sort(ALL(events));
std::vector<std::pair<int, int> > ans;
int cnt = 0;
int tl = -(1 << 30);
for (auto e : events) {
cnt += e.x;
if (cnt >= k) {
if (tl == -(1 << 30)) tl = e.l;
} else {
if (tl != -(1 << 30)) {
ans.push_back({tl, e.l - 1});
tl = -(1 << 30);
}
}
}
printf("%d\n", (int) ans.size());
for (auto v : ans) printf("%d %d\n", v.fi / 2, v.se / 2);
return 0;
}
E. Square Root of Permutation
首先把这个排列看成一个图论模型,\(a_i = j\) 表示一条 \(i \rightarrow j\) 的边
于是这样会形成若干个环,手玩一下可以发现,把一个排列进行平方之后,一个偶环会分裂成两个大小相等的偶环,而一个奇环还是一个奇环。
开平方根的过程就是平方的逆过程,所以,在开方之后,两个相同大小的偶环将会合并,而一个奇环合并不合并均可(我们贪心地选择不合并)。如果某种大小的偶环有奇数个即是无解。
const int MAXN = 1e6 + 10;
int n, oq[MAXN];
bool vis[MAXN];
std::vector<int> now;
void dfs(int u) {
if (vis[u]) return;
now.push_back(u); vis[u] = true;
dfs(oq[u]);
}
std::vector<std::vector<int> > ecirc[MAXN];
int ans[MAXN];
void GetAns(std::vector<int> &vec) {
for (int i = 0; i < (int) vec.size(); ++i) ans[vec[i]] = vec[(i + 1) % vec.size()];
}
int main() {
std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
n = read(); rep (i, 1, n) oq[i] = read();
rep (i, 1, n) {
if (vis[i]) continue;
now.clear(); dfs(i);
if (now.size() & 1) {
// odd circle
std::vector<int> res(now.size());
for (int j = 0, nx = 0; j < (int) now.size(); ++j, (nx += 2) %= now.size())
res[nx] = now[j];
GetAns(res);
} else ecirc[now.size()].push_back(now);
}
rep (sz, 1, n) {
if (!ecirc[sz].size()) continue;
if (ecirc[sz].size() & 1) {
puts("-1"); return 0;
}
for (int i = 0; i < (int) ecirc[sz].size(); i += 2) {
std::vector<int> &v1 = ecirc[sz][i], &v2 = ecirc[sz][i + 1];
std::vector<int> res(sz * 2);
for (int j = 0; j < sz; ++j) {
res[j << 1] = v1[j]; res[j << 1 | 1] = v2[j];
}
GetAns(res);
}
}
rep (i, 1, n) printf("%d ", ans[i]);
puts("");
return 0;
}