Rayan Programming Contest 2024 - Selection (Codeforces Round 989, Div. 1 + Div. 2) 补题记录(A~E)

A

答案显然就是 \(\text{lcm}(a,b)\)

void run() {
    int T = read();
    while (T--) {
        int a = read(), b = read();
        cout << a / __gcd(a, b) * b << '\n';
    }
}

B

考虑贪心模拟。若当前枚举到位置 \(i\) 时恰有 \(m\) 个连续的 \(0\),则从这个位置开始将后面连续的 \(k\) 个位置全部赋值为 \(1\)。容易证明这是正确的。

时间复杂度为 \(O(n)\)

char s[N];
void run() {
    int T = read();
    while (T--) {
        int n = read(), m = read(), k = read();
        scanf("%s", s + 1);
        int cnt = 0, sum = 0;
        for (int i = 1; i <= n; ++i) {
            if (s[i] == '0') {
                ++cnt;
                if (cnt >= m) {
                    ++sum;
                    int j, x;
                    for (j = i, x = 1; j <= n && x <= k; ++j, ++x)
                        s[j] = '1';
                    i = j - 1;
                    cnt = 0;
                }
            } else {
                cnt = 0;
            }
        }
        cout << sum << '\n';
    }
}

C

考虑这样的一个策略:

  • 若存在一个只包含 ? 的四连通块满足该块内 ? 的数目不小于 \(2\),则考虑任选两个相邻的 ? 并让它们互相只想对方,其余的 ? 都指向这两个 ? 中的一个。
  • 若某一个 ? 四联通的某一个位置不是 ?,且从该位置出发会无限循环,则让这个 ? 指向这个位置。
  • 剩下的位置随便指向任意一个位置。

容易证明该策略正确。若把指向关系显示建图则形成一个基环森林,维护的话可以使用并查集和 dfs 找环。总时间复杂度为 \(O(\alpha nm)\)

代码可能有点难写。

char s[2010][2010];
int id[2010][2010], fa[N], fm[N];
int find(int x) {
    return x == fa[x] ? x : fa[x] = find(fa[x]);
}
const int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0};
int vis[2010][2010], n, m, dfn;
int dfs(int x, int y) {
    assert(s[x][y] != '?');
    if (x < 1 || y < 1 || x > n || y > m) return 0;
    if (vis[x][y] == dfn)
        return 1;
    else if (vis[x][y] && fm[id[x][y]])
        return 1;
    else if (vis[x][y])
        return 0;
    vis[x][y] = dfn;
    if (s[x][y] == 'U') {
        if (dfs(x - 1, y)) {
            fm[id[x][y]] = 1;
            return 1;
        }
    }
    if (s[x][y] == 'D') {
        if (dfs(x + 1, y)) {
            fm[id[x][y]] = 1;
            return 1;
        }
    }
    if (s[x][y] == 'L') {
        if (dfs(x, y - 1)) {
            fm[id[x][y]] = 1;
            return 1;
        }
    }
    if (s[x][y] == 'R') {
        if (dfs(x, y + 1)) {
            fm[id[x][y]] = 1;
            return 1;
        }
    }
    return 0;
}
void run() {
    // freopen("1.in", "r", stdin);
    // freopen("1.out", "w", stderr);
    int T = read(), ca = 1;
    while (T--) {
        n = read(), m = read();
        for (int i = 1; i <= n; ++i)
            scanf("%s", s[i] + 1);
        // if (ca++ == 41) {
        //     for (int i = 1; i <= n; ++i, cerr << '\n')
        //         for (int j = 1; j <= m; ++j) cerr << s[i][j];
        // }
        dfn = 0;
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= m; ++j)
                if (s[i][j] == '?')
                    for (int d = 0; d < 4; ++d) {
                        int ii = i + dx[d], jj = j + dy[d];
                        if (ii >= 1 && ii <= n && jj >= 1 && jj <= m && s[ii][jj] == '?') {
                            if (d == 0) s[i][j] = 'R', s[ii][jj] = 'L';
                            else if (d == 2) s[i][j] = 'L', s[ii][jj] = 'R';
                            else if (d == 1) s[i][j] = 'D', s[ii][jj] = 'U';
                            else s[i][j] = 'U', s[ii][jj] = 'D';
                            break;
                        }
                    }
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= m; ++j)
                if (s[i][j] == '?')
                    for (int d = 0; d < 4; ++d) {
                        int ii = i + dx[d], jj = j + dy[d];
                        if (ii >= 1 && ii <= n && jj >= 1 && jj <= m) {
                            if (s[ii][jj] != '?') {
                                int ok = 0;
                                if (s[ii][jj] == 'L' && d == 0) s[i][j] = 'R', ok = 1;
                                else if (s[ii][jj] == 'R' && d == 2) s[i][j] = 'L', ok = 1;
                                else if (s[ii][jj] == 'U' && d == 1) s[i][j] = 'D', ok = 1;
                                else if (s[ii][jj] == 'D' && d == 3) s[i][j] = 'U', ok = 1;
                                if (ok) break;
                            }
                        }
                    }
        // for (int i = 1; i <= n; ++i, cout << '\n')
        //     for (int j = 1; j <= m; ++j) cout << s[i][j];
        int idx = 0;
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= m; ++j) {
                ++idx;
                id[i][j] = idx;
                fa[idx] = idx;
                fm[idx] = 0;
                vis[i][j] = 0;
            }
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= m; ++j)
                if (s[i][j] != '?')
                    ++dfn, dfs(i, j);
        // for (int i = 1; i <= n; ++i, cout << '\n')
        //     for (int j = 1; j <= m; ++j) cout << s[i][j];
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= m; ++j)
                if (s[i][j] != '?') {
                    int ii, jj;
                    if (s[i][j] == 'L') ii = i, jj = j - 1;
                    else if (s[i][j] == 'R') ii = i, jj = j + 1;
                    else if (s[i][j] == 'U') ii = i - 1, jj = j;
                    else ii = i + 1, jj = j;
                    if (ii >= 1 && ii <= n && jj >= 1 && jj <= m) {
                        int x = find(id[i][j]), y = find(id[ii][jj]);
                        if (x != y) fm[y] |= fm[x], fa[x] = y;
                    }
                }
        // for (int i = 1; i <= n * m; ++i) cout << fm[i] << ' ';
        // cout << '\n';
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= m; ++j)
                if (s[i][j] == '?')
                    for (int d = 0; d < 4; ++d) {
                        int ii = i + dx[d], jj = j + dy[d];
                        if (ii >= 1 && ii <= n && jj >= 1 && jj <= m) {
                            assert(s[ii][jj] != '?');
                            if (fm[find(id[ii][jj])]) {
                                if (d == 0) s[i][j] = 'R';
                                else if (d == 2) s[i][j] = 'L';
                                else if (d == 1) s[i][j] = 'D';
                                else s[i][j] = 'U';
                                int x = find(id[ii][jj]), y = find(id[i][j]);
                                if (x != y) fm[y] |= fm[x], fa[x] = y;
                                break;
                            }
                        }
                    }
        int cnt = 0;
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= m; ++j)
                cnt += fm[find(id[i][j])];
        // for (int i = 1; i <= n; ++i, cout << '\n')
        //     for (int j = 1; j <= m; ++j) cout << s[i][j];
        cout << cnt << '\n';
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= m; ++j) {
                id[i][j] = 0;
                fa[idx] = 0;
                s[i][j] = 0;
                fm[idx] = 0;
                vis[i][j] = 0;
            }
    }
}

D

比 C 简单。考虑用 set 来维护当前所有 \(0,1,2\) 的位置。每一次找到最后一个 \(0\) 和最前一个 \(1\)(需要满足最后一个 \(0\) 在最前一个 \(1\) 后面)或最后一个 \(2\) 和最前一个 \(1\)(需要满足最后一个 \(2\) 在最前一个 \(1\) 后面)交换。容易证明该策略正确。判断当前数组是否有序可以维护当前所有出现过的不同数字,然后用 set 找到当前数字最前和最后的位置就行了。

时间复杂度为 \(O(n\log n)\),自带大常数(雾

int a[N];
void run() {
    int T = read(), ca = 1;
    while (T--) {
        int n = read();
        for (int i = 1; i <= n; ++i)
            a[i] = read();
        set<int> buc[3];
        for (int i = 1; i <= n; ++i)
            if (a[i] == 0) buc[0].insert(i);
            else if (a[i] == 1) buc[1].insert(i);
            else buc[2].insert(i);
        auto chk = [&](void) {
            int cnt = 0;
            vector<int> id;
            for (int i = 0; i < 3; ++i)
                if (buc[i].size()) ++cnt, id.eb(i);
            if (cnt == 1) return 1;
            else if (cnt == 2) {
                if (*buc[id[0]].rbegin() < *buc[id[1]].begin()) return 1;
                return 0;
            } else {
                if (*buc[0].rbegin() < *buc[1].begin() && *buc[1].rbegin() < *buc[2].begin()) return 1;
                return 0;
            }
        };
        vector<pair<int, int>> op;
        while (!chk()) {
            if (buc[0].size() && buc[1].size()) {
                int x = *buc[0].rbegin(), y = *buc[1].begin();
                if (x > y) {
                    op.eb(x, y);
                    buc[0].erase(x);
                    buc[1].erase(y);
                    buc[0].insert(y);
                    buc[1].insert(x);
                }
            }
            if (chk()) break;
            if (buc[1].size() && buc[2].size()) {
                int x = *buc[1].rbegin(), y = *buc[2].begin();
                if (x > y) {
                    op.eb(x, y);
                    buc[1].erase(x);
                    buc[2].erase(y);
                    buc[1].insert(y);
                    buc[2].insert(x);
                }
            }
        }
        cout << op.size() << '\n';
        for (auto &[x, y] : op)
            cout << x << ' ' << y << '\n';
    }
}

E

大分类讨论。

  • \(n=1\)。此时若 \(k=1\) 则需构造排列 \(\lbrace 1\rbrace\)。否则无解。
  • \(n\neq 1\)\(k=1\)。此时显然无解。
  • \(2\mid k\)。先考虑 \(k=2\) 的特殊情况。显然可以构造 \(\lbrace 1,2,3,\ldots,n\rbrace\)\(\lbrace n,n-1,n-2,\ldots,1\rbrace\)。同样的若 \(2\mid k\) 则可以构造 \(1\sim n\) 组成的排列中字典序前 \(\frac{k}{2}\) 小的排列和字典序前 \(\frac{k}{2}\) 的排列。特殊点,若 \(n!<k\) 则无解。
  • \(k-1\mid n-1\)。此时令 \(d=\frac{n-1}{d-1}\),可以构造 \(k\) 个排列。其中第 \(i\) 个排列(\(i<k\))为 \(\lbrace 1+(d-1)i,2+(d-1)i,\ldots,n,1,2,\ldots,(d-1)i\rbrace\)。最后一个排列直接让每一个位置所对应元素的和相等即可。
  • \(2\nmid n\)。此时考虑到 \(k\ge 3\)\(2\nmid k\),所以考虑先用上面的方法构造 \(k=3\) 的排列,对于另外 \(n-3\) 个排列用偶数的构造方法。特殊的,若 \(n!+3<k\) 则无解。
  • 其余情况无解。

时间复杂度为 \(O(nk)\),可以通过。

int sjh[N], p1[N], p2[N], n, k;
void run() {
    int T = read(), ca = 1;
    while (T--) {
        n = read(), k = read();
        if (n == 1) {
            if (k == 1) {
                cout << "YES\n";
                for (int i = 1; i <= k; ++i) cout << "1\n";
            } else {
                cout << "NO\n";
            }
        } else if (k == 1) cout << "NO\n";
        else if (~k & 1) {
            int fac = 1;
            if (n > 12) fac = LLONG_MAX;
            else {
                for (int i = 1; i <= n; ++i)
                    fac = fac * i;
            }
            if (fac < k) cout << "NO\n";
            else {
                cout << "YES\n";
                iota(a + 1, a + n + 1, 1ll);
                for (int i = 0; i < k / 2; ++i) {
                    for (int j = 0; j < n; ++j) cout << a[j + 1] << ' ';
                    cout << '\n'; 
                    next_permutation(a + 1, a + n + 1);
                }
                iota(a + 1, a + n + 1, 1ll);
                reverse(a + 1, a + n + 1);
                for (int i = 0; i < k / 2; ++i) {
                    for (int j = 0; j < n; ++j) cout << a[j + 1] << ' ';
                    cout << '\n'; 
                    prev_permutation(a + 1, a + n + 1);
                }
            }
        } else {
            if (n == k) {
                cout << "YES\n";
                for (int i = 1; i <= n; ++i, cout << '\n') {
                    int j = i;
                    for (int x = 1; x <= n; ++x) {
                        cout << j << ' ';
                        ++j;
                        if (j > n) j = 1;
                    }
                }
            } else {
                if ((n - 1) % (k - 1) == 0) {
                    cout << "YES\n";
                    for (int i = 0; i < n; ++i) sjh[i] = 0;
                    int dt = (n - 1) / (k - 1), st = 1;
                    while (k--) {
                        if (k) {
                            int x = st;
                            for (int i = 0; i < n; ++i) {
                                cout << x << ' ';
                                sjh[i] += x;
                                ++x;
                                if (x > n) x = 1;
                            }
                            cout << '\n';
                        } else {
                            int all = st + sjh[0];
                            for (int i = 0; i < n; ++i)
                                cout << all - sjh[i] << ' ';
                            cout << '\n';
                        }
                        st += dt;
                    }
                } else {
                    int fac = 1;
                    if (n > 12) fac = LLONG_MAX;
                    else {
                        for (int i = 1; i <= n; ++i)
                            fac = fac * i;
                    }
                    fac -= 3;
                    if (fac < k) cout << "NO\n";
                    else if (n % 2 == 1) {
                        cout << "YES\n";
                        vector<vector<int>> p; p.resize(3);
                        for (int i = 0; i < 3; ++i) p[i].resize(n);
                        fill(sjh, sjh + n, 0ll);
                        for (int i = 0; i < n; ++i) p[0][i] = i + 1, sjh[i] = i + 1;
                        int st = n / 2 + 1; for (int i = 0; i < n; ++i) {
                            p[1][i] = st; ++st; if (st > n) st = 1;
                            sjh[i] += p[1][i];
                        }
                        int all = n + sjh[0];
                        for (int i = 0; i < n; ++i) p[2][i] = all - sjh[i];
                        iota(p1 + 1, p1 + n + 1, 1ll);
                        iota(p2 + 1, p2 + n + 1, 1ll);
                        reverse(p2 + 1, p2 + n + 1);
                        k -= 3; k /= 2;
                        for (int i = 0; i < 3; ++i, cout << '\n')
                            for (int j = 0; j < n; ++j) cout << p[i][j] << ' ';
                        while (k--) {
                            int o[6] = {1, 1, 1, 1, 1, 1};
                            for (int i = 1; i <= n; ++i) if (p1[i] != p[0][i - 1]) o[0] = 0;
                            for (int i = 1; i <= n; ++i) if (p1[i] != p[1][i - 1]) o[1] = 0;
                            for (int i = 1; i <= n; ++i) if (p1[i] != p[2][i - 1]) o[2] = 0;
                            for (int i = 1; i <= n; ++i) if (p2[i] != p[0][i - 1]) o[3] = 0;
                            for (int i = 1; i <= n; ++i) if (p2[i] != p[1][i - 1]) o[4] = 0;
                            for (int i = 1; i <= n; ++i) if (p2[i] != p[2][i - 1]) o[5] = 0;
                            if (count(o, o + 6, 1ll) == 0) {
                                for (int i = 1; i <= n; ++i) cout << p1[i] << ' '; cout << '\n';
                                for (int i = 1; i <= n; ++i) cout << p2[i] << ' '; cout << '\n';
                            } else ++k;
                            next_permutation(p1 + 1, p1 + n + 1);
                            prev_permutation(p2 + 1, p2 + n + 1);
                        }
                    } else {
                        cout << "NO\n";
                    }
                }
            }
        }
    }
}
posted @   yhbqwq  阅读(143)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 【.NET】调用本地 Deepseek 模型
点击右上角即可分享
微信分享提示