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;
}
posted @ 2021-10-19 15:59  Handwer  阅读(26)  评论(0编辑  收藏  举报