Codeforces Round #609 (Div. 1) – 解题报告

A – Long Beautiful Integer

取前\(k\)做循环节,并且对之后的每一个长为\(k\)的节进行大小比较,如果第一循环节小了就加个一即可。

// CF1268A.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 2e5 + 200;

int n, k;
char str[MAX_N];
int digits[MAX_N];

int main()
{
    scanf("%d%d%s", &n, &k, str + 1);
    for (int i = 1; i <= n; i++)
        digits[i] = str[i] - '0';
    // compare the nxt substr;
    bool flag = false;
    for (int i = k + 1; i <= n; i++)
        if (digits[(i - 1) % k + 1] > digits[i])
            break;
        else if (digits[(i - 1) % k + 1] < digits[i])
        {
            flag = true;
            break;
        }
    if (flag)
        digits[k]++;
    for (int i = k; i >= 1; i--)
        if (digits[i] >= 10)
            digits[i] -= 10, digits[i - 1]++;
    printf("%d\n", n);
    for (int i = 1; i <= n; i++)
        printf("%d", digits[(i - 1) % k + 1]);
    return 0;
}

C – K Integers

这道题还蛮有意思的。我们考虑最后答案应该是先把子段拼出来,然后再内部排序。内部排序的就可以动态维护一下逆序对即可,那么拼成子段就比较麻烦。不妨把\([1, k]\)的数字都设为\(1\),剩下的设置为\(0\)。那么,我们现在就是要把一堆\(1\)拼在一起。我们可以枚举子段的中点,然后把这些\(1\)向该点靠近,然后算出移动代价。可以发现这就有点像货仓选址,二分找下即可。

// CF1268C.cpp
#include <bits/stdc++.h>
#define ll long long

using namespace std;

const int MAX_N = 2e5 + 200;

ll n, pi[MAX_N], pos[MAX_N], nodes[2][MAX_N], inv_f[MAX_N], ans[MAX_N];
bool vis[MAX_N];

inline int lowbit(int x) { return x & (-x); }

void update(int id, int x, ll d)
{
    for (; x <= n; x += lowbit(x))
        nodes[id][x] += d;
}

ll query(int id, int x, ll ret = 0)
{
    for (; x > 0; x -= lowbit(x))
        ret += nodes[id][x];
    return ret;
}

int main()
{
    scanf("%lld", &n);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &pi[i]), pos[pi[i]] = i;
    for (int i = 1; i <= n; i++)
    {
        inv_f[i] = inv_f[i - 1] + i - query(0, pos[i]) - 1;
        update(0, pos[i], 1);
    }
    memset(nodes[0], 0, sizeof(nodes[0]));
    ll LB = n, RB = 1;
    for (int i = 1; i <= n; i++)
        update(0, i, 1), update(1, i, i), vis[i] = true;
    for (int i = 1; i <= n; i++)
    {
        LB = min(LB, pos[i]), RB = max(RB, pos[i]);
        update(0, pos[i], -1), update(1, pos[i], -pos[i]), vis[pos[i]] = false;
        int l = LB, r = RB, res = LB;
        while (l <= r)
        {
            int mid = (l + r) >> 1;
            int l_key = query(0, mid - 1) - query(0, LB);
            int r_key = query(0, RB) - query(0, mid);
            l_key = mid - LB - l_key, r_key = RB - mid - r_key;
            if (l_key <= r_key)
                res = mid, l = mid + 1;
            else
                r = mid - 1;
        }
        ll k1 = query(1, res) - query(1, LB), k1_ = query(0, res) - query(0, LB);
        ll k2 = query(1, RB) - query(1, res), k2_ = query(0, RB) - query(0, res);
        ans[i] = (k1 - k1_ * LB - (k1_ * (k1_ - 1) / 2)) + (k2_ * RB - k2 - (k2_ * (k2_ - 1) / 2));
    }
    for (int i = 1; i <= n; i++)
        printf("%lld ", inv_f[i] + ans[i]);
    return 0;
}

 

Leave a Reply

Your email address will not be published. Required fields are marked *