The 2021 ICPC Asia Regionals Online Contest (II)

Posted Kelin__

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了The 2021 ICPC Asia Regionals Online Contest (II)相关的知识,希望对你有一定的参考价值。

比赛链接

A. Sort

暴力

  1. k = 1 k=1 k=1 检查数组是否有序;
  2. k = 2 k=2 k=2 相当于再环上找个起点使得数组有序,直接判断;
  3. k ≥ 3 k\\ge 3 k3 考虑插入排序,每次暴力找到第 i i i 小的数的位置 p i p_i pi ,构造 0   p i − 1   p i   n 0\\ p_i-1\\ p_i\\ n 0 pi1 pi n 和排列 1   3   2 1\\ 3\\ 2 1 3 2 将第 i i i 小的放到最后面,重复 n n n 次即可,段数和 ≤ 3 n \\le 3n 3n 满足要求。

O ( n 2 ) O(n^2) O(n2)

#include<bits/stdc++.h>

using namespace std;
const int N = 1e3 + 5;
int n, k, a[N], b[N];
void Solve() {
    for (int i = 1; i <= n; ++i) scanf("%d", a + i), b[i] = a[i];
    if (is_sorted(a + 1, a + n + 1))
        return puts("0"), void();
    if (k == 1) return puts("-2"), void();
    if (k == 2) {
        int i = n;
        for (; i; --i) if (a[i - 1] > a[i]) break;
        if (a[n] > a[1] || !is_sorted(a + 1, a + i)) puts("-2");
        else printf("1\\n2\\n0 %d %d\\n2 1\\n", i - 1, n);
        return;
    }
    vector<int> v;
    int *c = b + 1;
    sort(b + 1, b + n + 1);
    for (int i = 1, j; i <= n; ++i, ++c) {
        for (j = 1; j <= n - i + 1; ++j) if (a[j] == *c) break;
        if (j == n) continue;
        v.push_back(j);
        for (int t = j; t <= n - i; ++t) a[t] = a[t + 1];
    }
    printf("%d\\n", (int) v.size());
    for (auto x: v)
        if (x == 1) printf("2\\n0 %d %d\\n2 1\\n", x, n);
        else printf("3\\n0 %d %d %d\\n1 3 2\\n", x - 1, x, n);
}
int main() {
    int T; scanf("%d", &T);
    while (T--) scanf("%d%d", &n, &k), Solve();
    return 0;
}

树状数组

先预处理出最初第 i i i 小的数的位置 p i p_i pi ,将 i i i 挪到最后相当于对所有 p j > p i p_j>p_i pj>pi 减 1 ,那么第 i i i 小的数的真实位置应该为 p i − ∑ j < i [ p j < p i ] \\displaystyle p_i-\\sum_{j<i}[p_j<p_i] pij<i[pj<pi] 。用树状数组维护顺序对即可。

O ( n log ⁡ n ) O(n\\log n) O(nlogn)

#include<bits/stdc++.h>

using namespace std;
const int N = 2e5 + 5;
int n, k, a[N], c[N], p[N];
void mdy(int i, int w) { for (; i <= n; i += i & -i) c[i] += w; }
int qry(int i, int w = 0) { for (; i; i -= i & -i) w += c[i]; return w; }
void Solve() {
    for (int i = 1; i <= n; ++i) scanf("%d", a + i), p[i] = i, c[i] = 0;
    if (is_sorted(a + 1, a + n + 1))
        return puts("0"), void();
    if (k == 1) return puts("-2"), void();
    if (k == 2) {
        int i = n;
        for (; i; --i) if (a[i - 1] > a[i]) break;
        if (a[n] > a[1] || !is_sorted(a + 1, a + i)) puts("-2");
        else printf("1\\n2\\n0 %d %d\\n2 1\\n", i - 1, n);
        return;
    }
    vector<int> v;
    sort(p + 1, p + n + 1, [&](int x, int y) { return a[x] < a[y]; });
    for (int i = 1, j; i <= n; ++i) {
        j = p[i] + qry(p[i]);
        if (j == n) continue;
        v.push_back(j), mdy(p[i], -1);
    }
    printf("%d\\n", (int) v.size());
    for (auto x: v)
        if (x == 1) printf("2\\n0 %d %d\\n2 1\\n", x, n);
        else printf("3\\n0 %d %d %d\\n1 3 2\\n", x - 1, x, n);
}
int main() {
    int T; scanf("%d", &T);
    while (T--) scanf("%d%d", &n, &k), Solve();
    return 0;
}

B. Mailman

经过的路径总是一条欧拉回路,所以题目可以转化为动态修改某个点度数,并询问将所有点度数变为偶数的最小花费。

由于 n ≤ 3 n\\le 3 n3 ,考虑对列建线段树,每个节点维护中间节点度数全为偶数,且左右侧节点度数状态分别为 S , T S,T S,T 的最小花费。

合并的时候 O ( 2 3 n ) O(2^{3n}) O(23n) 枚举左右和中间的状态,只用横向边连接。

注意当 L + 1 = R   /   m i d + 1 = R L+1=R\\ /\\ mid+1=R L+1=R / mid+1=R 的时候,中间连的边会改变左右端点的状态。

修改点度直接递归到叶子暴力修改然后向上合并即可。

O ( 2 3 n ( m + q ) log ⁡ m ) O(2^{3n}(m+q)\\log m) O(23n(m+q)logm)

#include<bits/stdc++.h>

#define fp(i, a, b) for(int i = (a), _##i = (b) + 1; i < _##i; ++i)
using namespace std;
using ll = int64_t;
const ll Inf = 1e18;
const int N = 5e4 + 5;
int k, n, q, a[N][2]; ll b[N][8]; // 3 * 1e9 > int
void cmin(ll &x, ll y) { x > y ? x = y : 0; }
struct Seg {
    ll tr[N << 2][8][8];
#define lc (p << 1)
#define rc (p << 1 | 1)
    void Up(int p, int L, int R) {
        int m = (L + R) >> 1;
        fp(i, 0, k) fp(j, 0, k) tr[p][i][j] = Inf;
        if (L + 1 == R) fp(i, 0, k) fp(j, 0, k) fp(t, 0, k) cmin(tr[p][i ^ t][j ^ t], tr[lc][i][i] + b[m][t] + tr[rc][j][j]);
        else if (m + 1 == R) fp(i, 0, k) fp(j, 0, k) fp(t, 0, k) cmin(tr[p][i][j ^ t], tr[lc][i][t] + b[m][t] + tr[rc][j][j]);
        else fp(i, 0, k) fp(j, 2021ICPC网络赛第二场The 2021 ICPC Asia Regionals Online Contest (II) L Euler Function

The 2021 ICPC Asia Regionals Online Contest (II)

The 2021 ICPC Asia Regionals Online Contest (II) M Addition

[树形DP] The 2021 ICPC Asia Nanjing Regional Contest H题

The 46th ICPC Asia Jinan Regional Contest,2021,46届济南站热身赛

The 2019 ICPC Asia Shanghai Regional Contest