Codeforces Round 744 (Div. 3)

摘要
A,B,C,D,E1,E2(树状数组求逆序对)

Powered by:NEFU AB-IN

Link

Codeforces Round #744 (Div. 3)

A. Casimir’s String Solitaire

  • 题意

    有两种操作

    • 同时删AABB
    • 同时删BBCC

    问一个字符串是否能删完

  • 思路

    就是看BB的个数和AACC的个数

  • 代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    /*
    * @Author: NEFU AB-IN
    * @Date: 2021-09-28 22:30:17
    * @FilePath: \ACM\CF\2021.9.28.div3\a.cpp
    * @LastEditTime: 2021-09-28 22:38:06
    */
    #include <bits/stdc++.h>
    using namespace std;
    #define LL long long
    #define MP make_pair
    #define SZ(X) ((int)(X).size())
    #define IOS \
    ios::sync_with_stdio(false); \
    cin.tie(0); \
    cout.tie(0);
    #define DEBUG(X) cout << #X << ": " << X << endl;
    typedef pair<int, int> PII;

    const int N = 1e4 + 10;

    signed main()
    {
    IOS;
    int t;
    cin >> t;
    while (t--)
    {
    string s;
    cin >> s;
    int a = 0, b = 0, c = 0;
    for (auto i : s)
    {
    if (i == 'A')
    a++;
    if (i == 'B')
    b++;
    if (i == 'C')
    c++;
    }
    if (b == a + c)
    cout << "YES\n";
    else
    cout << "NO\n";
    }
    return 0;
    }

B. Shifting Sort

  • 题意

    有一个长度为nn的数组aa,进行不超过nn次的操作,将数组转变为升序,问几次操作和每次操作的l,r,dl,r,d

    操作是选取一段区间[l,r][l,r],进行左移dd个单位的操作,溢出的元素补到后面

  • 思路

    类似于冒泡排序,一定正确的策略就是每次就把最小的移到最前面,然后对数组进行拼接的操作,即将最小的元素前面的元素拼接到数组后面,之后剔除第一个元素

    对于数组进行操作的,比较方便用PythonPython进行操作

  • 代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    '''
    Author: NEFU AB-IN
    Date: 2021-09-28 23:22:27
    FilePath: \ACM\CF\2021.9.28.div3\b.py
    LastEditTime: 2021-09-28 23:35:54
    '''
    import math

    def solve():
    n = int(input())
    l = list(map(int, input().split()))
    ll = []
    for i in range(n):
    id = l.index(min(l))
    if id != 0:
    ll.append([i + 1, n, id])
    l = (l[id:] + l[:id])[1:]
    print(len(ll))
    for i in ll:
    print(f"{i[0]} {i[1]} {i[2]}")


    for _ in range(int(input())):
    solve()

C. Ticks

  • 题意

    在包含*..的图中,有多个(包含00)由*组成的VV型图案,问*点是否都用来组成VVVV2d+12d+1个点组成,要求dkd \ge k

  • 思路

    大模拟即可,枚举每个*做为VV最底下那个点,并枚举dd,判断是否可以组成VV,如果可以,就给每个组成VV*打上标记即可,复杂度O(n3m)O(n^3m)

  • 代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    /*
    * @Author: NEFU AB-IN
    * @Date: 2021-09-29 00:20:19
    * @FilePath: \ACM\CF\2021.9.28.div3\c.cpp
    * @LastEditTime: 2021-09-29 00:46:32
    */
    #include <bits/stdc++.h>
    using namespace std;
    #define LL long long
    #define MP make_pair
    #define SZ(X) ((int)(X).size())
    #define IOS \
    ios::sync_with_stdio(false); \
    cin.tie(0); \
    cout.tie(0);
    typedef pair<int, int> pII;
    const int INF = 0x3f3f3f3f;

    const int N = 100;
    char a[N][N];
    bool f[N][N];

    void solve()
    {
    memset(f, 0, sizeof f);
    int n, m, k;
    cin >> n >> m >> k;
    for (int i = 1; i <= n; ++i)
    {
    for (int j = 1; j <= m; ++j)
    {
    cin >> a[i][j];
    }
    }
    for (int i = 1; i <= n; ++i)
    {
    for (int j = 1; j <= m; ++j)
    {
    if (a[i][j] == '*')
    {
    for (int d = k; d <= n; ++d)
    {
    int flag = 0;
    if (i - d < 1 || j - d < 1 || j + d > m)
    {
    break;
    }
    for (int kk = 1; kk <= d; ++kk)
    {
    if (a[i - kk][j - kk] != '*')
    {
    flag = 1;
    break;
    }
    }
    if (flag)
    continue;
    for (int kk = 1; kk <= d; ++kk)
    {
    if (a[i - kk][j + kk] != '*')
    {
    flag = 1;
    break;
    }
    }
    if (!flag)
    {
    f[i][j] = 1;
    for (int kk = 1; kk <= d; ++kk)
    {
    f[i - kk][j - kk] = 1;
    }
    for (int kk = 1; kk <= d; ++kk)
    {
    f[i - kk][j + kk] = 1;
    }
    }
    }
    }
    }
    }
    int flag = 0;
    for (int i = 1; i <= n; ++i)
    {
    for (int j = 1; j <= m; ++j)
    {
    if (a[i][j] == '*' && f[i][j] == 0)
    {
    flag = 1;
    cout << "NO\n";
    break;
    }
    }
    if (flag)
    break;
    }
    if (!flag)
    cout << "YES\n";
    }

    signed main()
    {
    IOS;
    int t;
    cin >> t;
    while (t--)
    {
    solve();
    }
    return 0;
    }

D. Productive Meeting

  • 题意

    nn个人,每个人有aia_i个谈话次数,每次可以两个人单独出来谈话一次,问最多可以谈话几次,并输出每次的人的编号

  • 思路

    很明显的大根堆的题,每次出来两个次数最多的谈话,谈话时间减完塞回到大根堆里

    注意

    • 大根堆元素只有11个时就退出
    • 每次出来的两个元素,有00了就退出
    • 如果减完时变成00,不加进大根堆
    • 存操作采用的双端队列dequedeque

    在这里记一下dequedeque

    • emplace_front() 代表从前面插入元素
    • emplace_back()代表从后面插入元素
    • pop_front()从前面弹出,从前出类似于
    • pop_back()从后面弹出,从后出就类似于队列
    • 都是O(1)O(1)的操作
    • 而且dequedeque具有可迭代性,即有cbegin() rbegin(),是队列和优先队列所没有的
  • 代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    /*
    * @Author: NEFU AB-IN
    * @Date: 2021-09-28 23:44:08
    * @FilePath: \ACM\CF\2021.9.28.div3\d.cpp
    * @LastEditTime: 2021-09-29 15:34:54
    */
    #include <bits/stdc++.h>
    using namespace std;
    #define LL long long
    #define MP make_pair
    #define SZ(X) ((int)(X).size())
    #define IOS \
    ios::sync_with_stdio(false); \
    cin.tie(0); \
    cout.tie(0);
    typedef pair<int, int> PII;
    const int INF = 0x3f3f3f3f;

    void solve()
    {
    int n;
    cin >> n;
    priority_queue<PII, vector<PII>> q;
    for (int i = 1; i <= n; ++i)
    {
    int x;
    cin >> x;
    q.push(MP(x, i));
    }
    deque<PII> Q;
    while (q.size() > 1)
    {
    PII x1 = q.top();
    q.pop();
    PII x2 = q.top();
    q.pop();
    if (x1.first == 0 || x2.first == 0)
    {
    break;
    }
    x1.first--;
    x2.first--;
    Q.emplace_front(MP(x1.second, x2.second));
    if (x1.first)
    q.push(x1);
    if (x2.first)
    q.push(x2);
    }
    cout << Q.size() << '\n';
    for (auto i : Q)
    {
    cout << i.first << " " << i.second << '\n';
    }
    }

    signed main()
    {
    IOS;
    int t;
    cin >> t;
    while (t--)
    {
    solve();
    }
    return 0;
    }

E1. Permutation Minimization by Deque

  • 题意

    给出一个排列,利用双端队列构造出字典序最小的序列

  • 思路

    按题意模拟即可,小的就放在前面即可,用vector会被卡,因为insertinsert复杂度为O(n)O(n),而deque操作为O(1)O(1)

  • 代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    /*
    * @Author: NEFU AB-IN
    * @Date: 2021-09-28 23:39:42
    * @FilePath: \ACM\CF\2021.9.28.div3\e1.cpp
    * @LastEditTime: 2021-09-29 16:36:31
    */
    #include <bits/stdc++.h>
    using namespace std;
    #define LL long long
    #define MP make_pair
    #define SZ(X) ((int)(X).size())
    #define IOS \
    ios::sync_with_stdio(false); \
    cin.tie(0); \
    cout.tie(0);
    #define DEBUG(X) cout << #X << ": " << X << endl;
    typedef pair<int, int> PII;

    void solve()
    {
    int n;
    cin >> n;
    deque<int> q;
    for (int i = 1; i <= n; i++)
    {
    int x;
    cin >> x;
    if (i == 0)
    {
    q.emplace_back(x);
    continue;
    }
    if (*q.begin() >= x)
    q.emplace_front(x);
    else
    q.emplace_back(x);
    }
    for (auto i : q)
    cout << i << " ";
    cout << '\n';
    }

    signed main()
    {
    IOS;
    int t;
    cin >> t;
    while (t--)
    {
    solve();
    }
    return 0;
    }

E2. Array Optimization by Deque

  • 题意

    给出一个排列,利用双端队列构造出逆序对最小的序列

  • 思路

    元素插入只有两种情况

    • 最前面,对后面的元素产生逆序对
    • 最后面,对前面的元素产生逆序对

    那么就每次插入的时候比较一下,两种情况的逆序对大小,每次加上小的就可以,tree[i]tree[i]还是正常加,相当于塞进去

    顺便复习了一遍树状数组求逆序对一定要离散化!!!

  • 代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    /*
    * @Author: NEFU AB-IN
    * @Date: 2021-09-29 18:19:55
    * @FilePath: \ACM\CF\2021.9.28.div3\e2.cpp
    * @LastEditTime: 2021-09-29 20:37:33
    */
    #include <bits/stdc++.h>
    using namespace std;
    #define LL long long
    #define MP make_pair
    #define SZ(X) ((int)(X).size())
    #define IOS \
    ios::sync_with_stdio(false); \
    cin.tie(0); \
    cout.tie(0);
    #define lowbit(x) ((x) & -(x))
    typedef pair<int, int> PII;
    const int INF = 0x3f3f3f3f;

    const int N = 1e6 + 10;
    LL tree[N], n, t[N], a[N];
    void add(LL x, LL d)
    {
    while (x <= n)
    {
    tree[x] += d;
    x += lowbit(x);
    }
    }
    LL sum(LL x)
    {
    LL sum = 0;
    while (x > 0)
    {
    sum += tree[x];
    x -= lowbit(x);
    }
    return sum;
    }

    void solve()
    {
    memset(tree, 0, sizeof tree);
    cin >> n;
    for (int i = 1; i <= n; ++i)
    {
    cin >> a[i];
    t[i] = a[i];
    }
    sort(t + 1, t + 1 + n);
    int m = unique(t + 1, t + 1 + n) - t - 1;
    for (int i = 1; i <= n; ++i)
    {
    a[i] = lower_bound(t + 1, t + 1 + m, a[i]) - t;
    }
    LL ans = 0;
    for (int i = 1; i <= n; ++i)
    {
    add(a[i], 1);
    ans += min(i - sum(a[i]), sum(a[i] - 1));
    }
    cout << ans << '\n';
    }

    signed main()
    {
    IOS;
    int t;
    cin >> t;
    while (t--)
    {
    solve();
    }
    return 0;
    }

完结。

使用搜索:谷歌必应百度