Codeforces Round 987 (Div. 2)(A-D)

A. Penchick and Modern Monument

思路

保留原来 n n n 个数中数量最多的一种数字,然后修改其他数使得序列不递减。

复杂度

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)

代码实现

cpp 复制代码
// Problem: A. Penchick and Modern Monument
// Contest: Codeforces - Codeforces Round 987 (Div. 2)
// URL: https://codeforces.com/contest/2031/problem/A
// Memory Limit: 256 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;

#define int long long

const int N = 5e4 + 5, M = 17;

int n;
int a[N];

void solve()
{
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    int ma = 0;
    for (int i = 1; i <= n; i++) {
        int j = i;
        while (j <= n && a[i] == a[j]) {
            j++;
        }
        ma = max(ma, j - i);
        i = j - 1;
    }
    int ans = n - ma;
    cout << ans << '\n';
}

signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
}

B. Penchick and Satay Sticks

思路

赛时思路:

发现形如 3 , 2 , 1 3,2,1 3,2,1 这样子安排, 1 1 1 是无法移动到第一个位置的,那么 1 1 1 开始时要么在第一个位置,要么在第二个位置,然后 2 2 2 在第一个位置。

当把 1 1 1 放到第一个位置的时候, 2 2 2 就变成了剩下 n − 1 n-1 n−1 个数的第一个数,也是进行相同的判断。

因此,可以从左到右遍历,如果 p i = i p_i = i pi=i,那么当前最小的数就安排好了位置,否则 p i ≠ i p_i \ne i pi=i,如果 p i + 1 ≠ i p_{i+1} \ne i pi+1=i 无解,否则交换 p i , p i + 1 p_i,p_{i+1} pi,pi+1,然后接着判断 p i + 1 p_{i+1} pi+1,直到判断完所有数为止。

题解思路:

如果数字 i i i 初始位置与 最后的位置 i i i 的距离超过 1 1 1,那么就无法把数字 i i i 移动到最后的位置。

因此,若 ∣ p i − i ∣ |p_i - i| ∣pi−i∣ 的最大值是大于 1 1 1 的,那么无解,否则有解。

复杂度

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)

代码实现

cpp 复制代码
// Problem: B. Penchick and Satay Sticks
// Contest: Codeforces - Codeforces Round 987 (Div. 2)
// URL: https://codeforces.com/contest/2031/problem/B
// Memory Limit: 256 MB
// Time Limit: 1500 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;

#define int long long

const int N = 2e5 + 5, M = 17;

int n;
int a[N];

void solve()
{
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    for (int i = 1; i <= n; i++) {
        if (a[i] != i) {
            if (i + 1 <= n && a[i + 1] == a[i] - 1) {
                swap(a[i], a[i + 1]);
            }
        }
        if (a[i] != i) {
            cout << "NO\n";
            return;
        }
    }
    cout << "YES\n";
}

signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
}

C. Penchick and BBQ Buns

思路

如果 n n n 为偶数,那么可以相邻的两个数两两作为一组,距离为 1 1 1 恰好是一个平方数。

如果 n n n 为奇数,手玩发现有解的最小奇数为 27 27 27。

因为不超过 27 27 27 的范围内有平方数 9 + 16 = 25 9+16=25 9+16=25,若答案序列为 a a a,可以令 a 1 , a 10 , a 26 a_1,a_{10},a_{26} a1,a10,a26 作为一组, a 11 , a 27 a_{11},a_{27} a11,a27 作为一组,然后剩下的数与相邻的数从左到右两两作为一组。

复杂度

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)

代码实现

cpp 复制代码
// Problem: C. Penchick and BBQ Buns
// Contest: Codeforces - Codeforces Round 987 (Div. 2)
// URL: https://codeforces.com/contest/2031/problem/C
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;

#define int long long

const int N = 5e4 + 5, M = 17;

void solve()
{
    int n;
    cin >> n;
    if (n % 2 == 0) {
        int p = 1;
        for (int i = 1; i <= n; i += 2) {
            cout << p << ' ' << p << ' ';
            p++;
        }
        cout << '\n';
    } else {
        if (n < 27) {
            cout << "-1\n";
            return;
        }
        int p = 1;
        vector<int> a(n + 1);
        a[1] = a[10] = a[26] = p++;
        for (int i = 2; i < 10; i += 2) {
            a[i] = a[i + 1] = p++;
        }
        a[11] = a[27] = p++;
        for (int i = 12; i < 26; i += 2) {
            a[i] = a[i + 1] = p++;
        }
        for (int i = 28; i <= n; i += 2) {
            a[i] = a[i + 1] = p++;
        }
        for (int i = 1; i <= n; i++) {
            cout << a[i] << ' ';
        }
        cout << '\n';
    }
}

signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
}

D. Penchick and Desert Rabbit

思路

如果区间 [ l , r ] [l,r] [l,r] 中的最大高度为 a l a_l al,那么 [ l , r ] [l,r] [l,r] 中的任意一个位置出发,可以向左跳到 l l l 位置,取得高度 a l a_l al。

如果区间 [ l 1 , r 1 ] [l_1,r_1] [l1,r1] 满足 l 1 > r l_1>r l1>r, a l 1 a_{l_1} al1 为 [ l 1 , r 1 ] [l_1,r_1] [l1,r1] 的最大值,且 a l 1 > a l a_{l_1}>a_l al1>al, [ l 1 , r 1 ] [l_1,r_1] [l1,r1] 的最小值小于 a l a_l al,那么从 [ l , r ] [l,r] [l,r] 中的任意位置出发,可以向左跳到 l l l 位置,然后再跳到 [ l 1 , r 1 ] [l_1,r_1] [l1,r1] 的最小值位置,在跳到 l 1 l_1 l1 位置,取得更大的高度 a l 1 a_{l_1} al1。

通过上面的思考,可以发现,如果 a i a_i ai 为 [ 1 , n ] [1,n] [1,n] 中的下标最小的最大值。(就是说如果存在多个最大值, i i i 是最大值下标中的最小下标。),那么从 [ i , n ] [i,n] [i,n] 中的任意位置出发,都可以跳到最大高度 a i a_i ai。

如果 [ 1 , i − 1 ] [1,i-1] [1,i−1] 中的下标最小的最大值为 a j a_j aj,那么从 [ j , i − 1 ] [j,i-1] [j,i−1] 中的任意位置出发,可以跳到高度 a j a_j aj。

如果要跳到高度 a i a_i ai,那么需要 [ i , n ] [i,n] [i,n] 中存在一个高度 a k < a j a_k < a_j ak<aj,也就是说 [ i , n ] [i,n] [i,n] 中的最小高度要小于 a j a_j aj,才能使得从 [ j , i − 1 ] [j,i-1] [j,i−1] 中的任意位置出发,能够跳到高度 a i a_i ai,否则能跳到的最大高度就是 a j a_j aj。

继续向左找下标最小的最大值,这样子会划分出若干个连续的子区间,满足上一个子区间的右端点加一为下一个子区间的左端点,子区间的左端点的值为整个子区间的最大值,且子区间的最大值是从右到左递减的。

(要快速找下标最小的最大值,可以先预处理出 s t st st 表,然后用 s t st st 表进行查询,下面找区间内的最小值同样也是可以用 s t st st 表。)

对于在同一个子区间内的位置,最终都能达到的高度都是相同的。

对于一个子区间 [ l , r ] [l,r] [l,r],如果右边存在一个子区间 [ l 1 , r 1 ] [l_1,r_1] [l1,r1]的最小高度小于子区间 [ l , r ] [l,r] [l,r] 的最大高度,那么子区间 [ l , r ] [l,r] [l,r] 内的位置可以达到的最大高度就可以为子区间 [ l 1 , r 1 ] [l_1,r_1] [l1,r1] 能达到的最大高度。

可能右边会存在多个子区间的最小高度,小于子区间 [ l , r ] [l,r] [l,r] 的最大高度,这些子区间中的最大高度的最大值,就是区间 [ l , r ] [l,r] [l,r] 内的位置可以达到的最大高度。

直接遍历右边子区间,看哪些子区间的最小高度大于区间 [ l , r ] [l,r] [l,r] 的最大高度,显然是会超时的。

可以用权值线段树进行维护,维护的单点 x x x 的数值,表示右边子区间的最小高度为 x x x 的能达到的最大高度。

当遍历到一个子区间 [ l , r ] [l,r] [l,r] 时,就可以查询最小高度在 [ 1 , a l − 1 ] [1,a_l-1] [1,al−1] 范围内的,右边的子区间能达到的最大高度,与 a l a_l al 比较取最大值,即是 [ l , r ] [l,r] [l,r] 能达到的最大高度。

遍历完子区间 [ l , r ] [l,r] [l,r] 后,就可以新该子区间最小高度的对应数值,然后求解区间 [ 1 , l − 1 ] [1,l-1] [1,l−1]。

复杂度

时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn),空间复杂度 O ( n log ⁡ n ) O(n \log n) O(nlogn)

代码实现

cpp 复制代码
// Problem: D. Penchick and Desert Rabbit
// Contest: Codeforces - Codeforces Round 987 (Div. 2)
// URL: https://codeforces.com/contest/2031/problem/D
// Memory Limit: 256 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
using namespace std;

#define int long long

const int N = 5e5 + 5, M = 20;

int n;
int f[N][M], g[N][M];
int a[N], ans[N];

int query_st(int l, int r, int op)
{
    int k = log2(r - l + 1);
    if (!op) {
        int id1 = f[l][k];
        int id2 = f[r - (1 << k) + 1][k];
        return a[id2] > a[id1] ? id2 : id1;
    } else {
        int id1 = g[l][k];
        int id2 = g[r - (1 << k) + 1][k];
        return a[id2] < a[id1] ? id2 : id1;
    }
}

struct {
    int l, r, v;
} tr[4 * N];

void build(int u, int l, int r)
{
    tr[u].l = l, tr[u].r = r, tr[u].v = 0;
    if (l != r) {
        int mid = (l + r) >> 1;
        build(u * 2, l, mid);
        build(u * 2 + 1, mid + 1, r);
    }
}

void pushup(int u)
{
    tr[u].v = max(tr[u * 2].v, tr[u * 2 + 1].v);
}

void modify(int u, int p, int x)
{
    if (tr[u].l == tr[u].r) {
        tr[u].v = max(tr[u].v, x);
        return;
    }
    int mid = (tr[u].l + tr[u].r) >> 1;
    if (p <= mid)
        modify(u * 2, p, x);
    else
        modify(u * 2 + 1, p, x);
    pushup(u);
}

int query(int u, int l, int r)
{
    if (l <= tr[u].l && tr[u].r <= r)
        return tr[u].v;

    int res = 0;
    int mid = (tr[u].l + tr[u].r) >> 1;
    if (l <= mid)
        res = max(res, query(u * 2, l, r));
    if (r > mid)
        res = max(res, query(u * 2 + 1, l, r));
    return res;
}

void solve()
{
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        ans[i] = 0;
    }
    for (int j = 0; j < M; j++) {
        int step = 1 << (j - 1);
        for (int i = 1; i + (1 << j) - 1 <= n; i++) {
            if (!j) {
                f[i][j] = g[i][j] = i;
            } else {
                f[i][j] = f[i][j - 1];
                if (a[f[i + step][j - 1]] > a[f[i][j]]) {
                    f[i][j] = f[i + step][j - 1];
                }
                g[i][j] = g[i][j - 1];
                if (a[g[i + step][j - 1]] < a[g[i][j]]) {
                    g[i][j] = g[i + step][j - 1];
                }
            }
        }
    }
    build(1, 1, n);

    int r = n;
    while (r >= 1) {
        int l = query_st(1, r, 0);
        int v = a[l];
        if (a[l] > 1) {
            v = max(query(1, 1, a[l] - 1), v);
        }
        for (int i = l; i <= r; i++) {
            ans[i] = v;
        }
        int w = a[query_st(l, r, 1)];
        modify(1, w, v);
        r = l - 1;
    }
    for (int i = 1; i <= n; i++) {
        cout << ans[i] << ' ';
    }
    cout << '\n';
}

signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    int T = 1;
    cin >> T;
    while (T--) {
        solve();
    }
}
相关推荐
清岚_lxn6 分钟前
es6 字符串每隔几个中间插入一个逗号
前端·javascript·算法
chenziang127 分钟前
leetcode hot 100 全排列
算法·leetcode·职场和发展
打鱼又晒网30 分钟前
Linux网络 | 网络计算器客户端实现与Json的安装以及使用
linux·c++·网络协议·计算机网络
lili-felicity35 分钟前
指针与数组:深入C语言的内存操作艺术
c语言·开发语言·数据结构·算法·青少年编程·c#
PengFly12337 分钟前
题解:[ABC294G] Distance Queries on a Tree
算法·lca·树状数组·dfs序
月亮邮递使light41 分钟前
代码随想录算法训练营第五十八天 | 拓扑排序精讲 dijkstra(朴素版)精讲
算法
野風_199602011 小时前
代码随想录第59天
算法
HappyAcmen1 小时前
青训营-豆包MarsCode技术训练营试题解析四十八
开发语言·python·算法
Zer0_on1 小时前
数据结构二叉树
开发语言·数据结构
码农老起1 小时前
插入排序解析:时间复杂度、空间复杂度与优化策略
数据结构·算法·排序算法