Codeforces Round 1017 (Div. 4) 题解(A~H)

A

Code

#pragma GCC optimize(3,"Ofast","inline","unroll-loops")
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/rope>
#define int long long
using namespace std;
const int N = 1000010;
const int inf = 2e9;
const int mod = 1e9 + 7;
using ull = unsigned long long;
template<class _T>
using treap = __gnu_pbds::tree<_T, __gnu_pbds::null_type, less_equal<_T>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update>;
int a[N];
signed main() {
    // freopen("debug.err", "w", stderr);
    cin.tie(0)->sync_with_stdio(false);
    cout << fixed << setprecision(15);
    srand(time(0));
    int T;
    cin >> T;
    while (T--) {
        string a, b, c;
        cin >> a >> b >> c;
        cout << a[0] << b[0] << c[0] << '\n';
    }
    return 0;
}

B

Code

#pragma GCC optimize(3,"Ofast","inline","unroll-loops")
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/rope>
#define int long long
using namespace std;
const int N = 1000010;
const int inf = 2e9;
const int mod = 1e9 + 7;
using ull = unsigned long long;
template<class _T>
using treap = __gnu_pbds::tree<_T, __gnu_pbds::null_type, less_equal<_T>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update>;
int a[N];
signed main() {
    // freopen("debug.err", "w", stderr);
    cin.tie(0)->sync_with_stdio(false);
    cout << fixed << setprecision(15);
    srand(time(0));
    int T;
    cin >> T;
    while (T--) {
        int n, m, l, r;
        cin >> n >> m >> l >> r;
        int diff = n - m;
        if (r >= diff) cout << l << ' ' << r - diff << '\n';
        else {
            diff -= r;
            r = 0;
            cout << l + diff << ' ' << r << '\n';
        }
    }
    return 0;
}

C

观察到 \(2\sim n+n\) 都可以直接在 \(a\) 中找出,因此只需要找没有出现过的数就是第一个元素的值

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

Code

#pragma GCC optimize(3,"Ofast","inline","unroll-loops")
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/rope>
#define int long long
using namespace std;
const int N = 1000010;
const int inf = 2e9;
const int mod = 1e9 + 7;
using ull = unsigned long long;
template<class _T>
using treap = __gnu_pbds::tree<_T, __gnu_pbds::null_type, less_equal<_T>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update>;
int a[810][810];
signed main() {
    // freopen("debug.err", "w", stderr);
    cin.tie(0)->sync_with_stdio(false);
    cout << fixed << setprecision(15);
    srand(time(0));
    int T;
    cin >> T;
    while (T--) {
        int n;
        cin >> n;
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= n; ++j)
                cin >> a[i][j];
        set<int> se;
        for (int i = 1; i <= n + n; ++i) se.emplace(i);
        for (int i = 1; i <= n; ++i) se.erase(a[1][i]);
        for (int i = 2; i <= n; ++i) se.erase(a[i][n]);
        cout << *se.begin() << ' ';
        for (int i = 1; i <= n; ++i) cout << a[1][i] << ' ';
        for (int i = 2; i <= n; ++i) cout << a[i][n] << ' ';
        cout << '\n';
    }
    return 0;
}

D

把两个字符串均划分为若干段连续的相同字符,合法则需要满足:

  • 两个字符串划分的段数相等,且对应段的字符也相同。
  • 假设第 \(i\) 段在 \(S\) 中长度为 \(c_1\),在 \(T\) 中长度为 \(c_2\),则需要满足 \(c_2\le c_1\le 2c_2\)

直接用两个指针扫描数组然后贪心模拟,时间复杂度为 \(O(n)\)

Code

#pragma GCC optimize(3,"Ofast","inline","unroll-loops")
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/rope>
#define int long long
using namespace std;
const int N = 1000010;
const int inf = 2e9;
const int mod = 1e9 + 7;
using ull = unsigned long long;
template<class _T>
using treap = __gnu_pbds::tree<_T, __gnu_pbds::null_type, less_equal<_T>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update>;
char s[N], t[N];
signed main() {
    // freopen("debug.err", "w", stderr);
    // cin.tie(0)->sync_with_stdio(false);
    cout << fixed << setprecision(15);
    srand(time(0));
    int T;
    cin >> T;
    while (T--) {
        scanf("%s%s", s + 1, t + 1);
        int n = strlen(s + 1), m = strlen(t + 1);
        int p1 = 1, p2 = 1, ok = 1;
        while (p1 <= n && p2 <= m) {
            int c1 = 0, c2 = 0, lp1 = p1, lp2 = p2;
            while (p1 <= n && s[p1] == s[lp1]) ++p1;
            while (p2 <= m && t[p2] == t[lp2]) ++p2;
            c1 = p1 - lp1, c2 = p2 - lp2;
            if (c1 <= c2 && 2 * c1 >= c2 && s[lp1] == t[lp2]) ;
            else {
                ok = 0;
                break;
            }
        }
        if (!ok) cout << "NO\n";
        else if ((p1 > n && p2 <= m) || (p1 <= n && p2 > m)) cout << "NO\n";
        else cout << "YES\n";
    }
    return 0;
}

E

拆位然后按位考虑答案,用前缀和维护即可,时间复杂度为 \(O(n\log V)\)

Code

#pragma GCC optimize(3,"Ofast","inline","unroll-loops")
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/rope>
#define int long long
using namespace std;
const int N = 200010;
const int inf = 2e9;
const int mod = 1e9 + 7;
using ull = unsigned long long;
template<class _T>
using treap = __gnu_pbds::tree<_T, __gnu_pbds::null_type, less_equal<_T>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update>;
int a[N];
int pre[N][32];
signed main() {
    // freopen("debug.err", "w", stderr);
    cin.tie(0)->sync_with_stdio(false);
    cout << fixed << setprecision(15);
    srand(time(0));
    int T;
    cin >> T;
    while (T--) {
        int n;
        cin >> n;
        for (int i = 1; i <= n; ++i) cin >> a[i];
        int mx = 0;
        for (int i = 1; i <= n; ++i) {
            for (int j = 0; j < 30; ++j)
                pre[i][j] = pre[i - 1][j] + (a[i] >> j & 1);
        }
        for (int i = 1; i <= n; ++i) {
            int sum = 0;
            for (int j = 0; j < 30; ++j) {
                int cnt = pre[i - 1][j] + (pre[n][j] - pre[i][j]);
                if (a[i] >> j & 1) cnt = n - 1 - cnt;
                sum += (1ll << j) * cnt;
            }
            mx = max(mx, sum);
        }
        cout << mx << '\n';
    }
    return 0;
}

F

分类讨论:若 \(k\) 可以被分为 \(x_1x_2\) 并满足 \(x_1,x_2>1,x_1\mid n,x_2\mid m\),则可以把数组划分为若干个 \(x_1\times x_2\) 的子数组然后直接按 \(1\sim k\) 的顺序给数组染色,否则必然满足 \(k\mid n\)\(k\mid m\),就直接按顺序染色然后为了避免相邻两个元素相同,轮换一下即可。

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

Code

#pragma GCC optimize(3,"Ofast","inline","unroll-loops")
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/rope>
#define int long long
using namespace std;
const int N = 200010;
const int inf = 2e9;
const int mod = 1e9 + 7;
using ull = unsigned long long;
template<class _T>
using treap = __gnu_pbds::tree<_T, __gnu_pbds::null_type, less_equal<_T>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update>;
int isprime(int x) {
    if(x < 2) return 0;
    for (int i = 2; i * i <= x; ++i)
        if (x % i == 0) return 0;
    return 1;
}
int pos[N];
signed main() {
    // freopen("debug.err", "w", stderr);
    cin.tie(0)->sync_with_stdio(false);
    cout << fixed << setprecision(15);
    srand(time(0));
    int T;
    cin >> T;
    while (T--) {
        int n, m, k;
        cin >> n >> m >> k;
        vector<vector<int>> a(n + 2);
        for (int i = 0; i < n + 2; ++i) a[i].resize(m + 2);
        if (n % k == 0) {
            // cerr << "wa\n";
            for (int i = 0; i <= n + 1; ++i) pos[i] = 1;
            for (int i = 0; i < m; ++i) {
                int start = 1;
                for (int j = 0; j < n; j += k) {
                    int nw = pos[j];
                    for (int p = j; p < j + k; ++p) {
                        a[p + 1][i + 1] = nw;
                        ++nw;
                        if (nw > k) nw = 1;
                    }
                    ++pos[j];
                    if (pos[j] > k) pos[j] = 1;
                }
            }
        } else if (m % k == 0) {
            for (int i = 0; i <= m + 1; ++i) pos[i] = 1;
            for (int i = 0; i < n; ++i) {
                int start = 1;
                for (int j = 0; j < m; j += k) {
                    int nw = pos[j];
                    for (int p = j; p < j + k; ++p) {
                        a[i + 1][p + 1] = nw;
                        ++nw;
                        if (nw > k) nw = 1;
                    }
                    ++pos[j];
                    if (pos[j] > k) pos[j] = 1;
                }
            }
        } else {
            vector<int> fact;
            for (int i = 2; i * i <= k; ++i)
                if (k % i == 0) {
                    fact.emplace_back(i);
                    fact.emplace_back(k / i);
                }
            int x = -1, y = -1;
            for (int &i : fact)
                if (n % i == 0 && m % (k / i) == 0) {
                    x = i, y = k / i;
                    break;
                }
            for (int i = 0; i < n; i += x) {
                for (int j = 0; j < m; j += y) {
                    int idx = 1;
                    for (int p = i; p < i + x; ++p)
                        for (int q = j; q < j + y; ++q)
                            a[p + 1][q + 1] = idx++;
                }
            }
        }
        for (int i = 0; i < n; ++i, cout << '\n')
            for (int j = 0; j < m; ++j) cout << a[i + 1][j + 1] << ' ';
    }
    return 0;
}

G

用双端队列随便维护一下答案,再打一个标记表示当前数组是否被翻转即可,时间复杂度为 \(O(n)\)

Code

#pragma GCC optimize(3,"Ofast","inline","unroll-loops")
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/rope>
#define int long long
using namespace std;
const int N = 200010;
const int inf = 2e9;
const int mod = 1e9 + 7;
using ull = unsigned long long;
template<class _T>
using treap = __gnu_pbds::tree<_T, __gnu_pbds::null_type, less_equal<_T>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update>;
int isprime(int x) {
    if(x < 2) return 0;
    for (int i = 2; i * i <= x; ++i)
        if (x % i == 0) return 0;
    return 1;
}
signed main() {
    // freopen("debug.err", "w", stderr);
    cin.tie(0)->sync_with_stdio(false);
    cout << fixed << setprecision(15);
    srand(time(0));
    int T;
    cin >> T;
    while (T--) {
        int q, n = 0;
        cin >> q;
        int pre = 0, sum = 0;
        deque<int> Q;
        int tag = 0;
        while (q--) {
            int o;
            cin >> o;
            if (o == 1) {
                if (!tag) {
                    sum += pre - n * Q.back();
                    Q.emplace_front(Q.back());
                    Q.pop_back();
                } else {
                    sum += pre - n * Q.front();
                    Q.emplace_back(Q.front());
                    Q.pop_front();
                }
            } else if (o == 2) {
                tag ^= 1;
                sum = pre * (n + 1) - sum;
            } else {
                int x;
                cin >> x;
                ++n;
                pre += x;
                sum += n * x;
                if (!tag) Q.emplace_back(x);
                else Q.emplace_front(x);
            }
            cout << sum << '\n';
        }
    }
    return 0;
}

H

观察到 \(k\) 最多减 \(\log V\) 次就会变成 \(1\),而 \(k=1\) 的情况是简单的,所以直接枚举因子二分出 \(k\) 的值下一次会在哪里减少,暴力模拟减少的过程即可。容易证明时间复杂度正确。

Code

#pragma GCC optimize(3,"Ofast","inline","unroll-loops")
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/rope>
#define int long long
using namespace std;
const int N = 100010;
const int inf = 2e9;
const int mod = 1e9 + 7;
using ull = unsigned long long;
template<class _T>
using treap = __gnu_pbds::tree<_T, __gnu_pbds::null_type, less_equal<_T>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update>;
int a[N];
vector<int> divi[N], scc[N];
signed main() {
    // freopen("debug.err", "w", stderr);
    cin.tie(0)->sync_with_stdio(false);
    cout << fixed << setprecision(15);
    srand(time(0));
    int T;
    cin >> T;
    for (int i = 2; i < N; ++i)
        for (int j = i; j < N; j += i)
            divi[j].emplace_back(i);
    while (T--) {
        int n, q;
        cin >> n >> q;
        for (int i = 1; i <= n; ++i) cin >> a[i], scc[a[i]].emplace_back(i);
        while (q--) {
            int k, l, r, sum = 0, ccf = 0, las = k;
            cin >> k >> l >> r;
            las = k;
            for (int i = l; i <= r; ) {
                if (las == 1) {
                    sum += r - i + 1;
                    break;
                }
                int ri = r + 1;
                for (int &j : divi[las])
                    if (scc[j].size()) {
                        auto it = lower_bound(scc[j].begin(), scc[j].end(), i);
                        if (it != scc[j].end() && *it <= r) ri = min(ri, *it);
                if (ri == r + 1) {
                    sum += (r - i + 1) * las;
                    break;
                } else {
                    sum += (ri - i) * las;
                    assert(las % a[ri] == 0);
                    while (las % a[ri] == 0) las /= a[ri];
                    sum += las, i = ri + 1;
                }
            }
            cout << sum << '\n';
        }
        for (int i = 1; i <= n; ++i) scc[a[i]].clear();
    }
    return 0;
}
posted @ 2025-04-14 20:33  0103abc  阅读(52)  评论(0)    收藏  举报