Featured image of post Codeforces Round #1006(Div.3)

Codeforces Round #1006(Div.3)

D

题目大意:Akito 厌倦了在银行当普通锁匠的工作,因此他决定进入魔法学院并成为世界上最强的巫师!然而,为了入学,他需要解决考试中的唯一一道题目,而这位雄心勃勃的英雄却未能成功。题目给定一个长度为 $n$ 的数组 $a$。Akito 需要在使用恰好一次咒语后,使数组中的逆序对数量 $^{\text{∗}}$ 最小化。咒语的使用方式很简单:Akito 必须选择两个数 $l$ 和 $r$(满足 $1 \le l \le r \le n$),并对子数组 $[l, r]$ 进行一次向左循环移位。

数据范围:$1 \le t \le 10^4$,$1 \le n \le 2000$,$1 \le a_i \le 2000$,$\sum n^2 \le 4 \cdot 10^6$。

思路:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
void solve() {
    int n;
    cin >> n;
    vl a(n);
    rep(i, 0, n - 1) cin >> a[i];
    int idx1 = -1, idx2 = -1;
    int maxx = INT_MIN;
    rep(i, 0, n - 1) {
        int tem = 0;
        int tem2 = 0;
        rep(j, i, n - 1) {
            tem += (a[j] < a[i]);
            tem2 += (a[j] > a[i]);
            if (tem - tem2 > maxx) {
                idx1 = i, idx2 = j;
                maxx = tem - tem2;
            }
        }
    }
    cout << idx1 + 1 << ' ' << idx2 + 1 << endl;
    return;
}

E

题目大意:Akito 决定学习一个强大的新咒语。由于这个咒语拥有无可估量的力量,它必然需要大量空间和精心准备。为此,Akito 来到了一片空地。我们将这片空地表示为一个笛卡尔坐标系。为了施展咒语,Akito 需要在空地的不同整数坐标处放置 $0 \le n \le 500$ 根法杖,使得恰好存在 $k$ 对 $(i, j)$ 满足 $1 \le i < j \le n$ 且 $\rho(i, j) = d(i, j)$。

数据范围:$1 \le t \le 1000$,$0 \le k \le 10^5$。

思路:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
void solve() {
    int k;
    cin >> k;
    vector<pii> ma;
    vl ma2;
    rep(i, 2, 499) ma2.emplace_back(i * (i - 1) / 2);
    int idx1 = 0, idx2 = 0;
    while (k > 0) {
        int tem2 = ranges::upper_bound(ma2, k) - ma2.begin() - 1;
        rep(i, 0, tem2 + 1) {
            ma.emplace_back(idx1, idx2);
            idx2++;
        }
        idx1++;
        k -= ma2[tem2];
    }
    cout << sz(ma) << endl;
    for (auto& p : ma) cout << p.first << ' ' << p.second << endl;
    return;
}

F

题目大意:怪物正在逼近城市,为了保护它,Akito 必须在城市周围创建一个防护场。众所周知,防护场有不同的等级。Akito 选择了等级为 $n$ 的防护场。为了构建这个防护场,需要一个特殊咒语,即伟大魔法三角(表示为二维数组 $T$)的第 $n$ 行。我们将这个数组称为 $T$。魔法三角的定义如下: - 第 $i$ 行包含 $i$ 个整数。- 第一行唯一的整数是 $k$。

数据范围:$1 \le t \le 10^4$,$1 \le n \le 10^6$,$1 \le k < 2^{31}$,$\sum n \le 10^6$。

思路:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
void solve() {
    int n, k;
    cin >> n >> k;
    vi a(n);
    frep(i, 31, 0) {
        if (((k >> i) & 1) == 0) continue;
        rep(j, 0, n - 1) { a[j] += (1 << i) * (((n - 1) & j) == j); }
    }
    rep(i, 0, n - 1) cout << a[i] << ' ';
    cout << endl;
    return;
}

G

题目大意:经过三百年的史莱姆养殖,Akito 终于获得了魔法数字 $n$。当他找到商人准备兑换黄金时,商人却给了他一个任务。商人表示,完成这个任务需要用到技能 $\text{rev}(n, p)$,而 Akito 恰好最近学会了这个技能。$\text{rev}(n, p)$ 表示以下操作流程: 1. 将数字 $n$ 以 $p$ 进制表示,记作 $n = \overline{n_{\ell - 1} \ldots n_1 n_0}$,其中 $\ell$ 是 $n$ 的 $p$ 进制表示的位数长度。2. 反转这个 $p$ 进制表示,得到 $m = \overline{n_0 n_1 \ldots n_{\ell - 1}}$。

数据范围:$1 \le t \le 5000$,$1 \le n \le 3 \cdot 10^5$,$2 \le k \le 10^{18}$。

思路:

 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
const ll MOD = 1e9 + 7;
const ll inv2 = 500000004;
const ll inv6 = 166666668;
void solve() {
    ll n, k;
    cin >> n >> k;
    ll ans = 0;
    ans += max(k - n, 0LL) % MOD * n % MOD;
    int B = (int)sqrt(n);
    rep(i, 2, min(k, n)) {
        if (i <= B) {
            ll res = 0;
            ll tem = n;
            while (tem) {
                res = (res * i % MOD + tem % i) % MOD;
                tem /= i;
            }
            ans = (ans + res) % MOD;
        } else {
            auto check = [&]() -> void {
                for (ll l = i, r; l <= min(k, n); l = r + 1) {
                    ll v = n / l;
                    r = min(min(n, k), n / v);
                    ll cnt = (r - l + 1) % MOD;
                    ans += n % MOD * (l + r) % MOD * cnt % MOD * inv2 % MOD;
                    ans = (ans + MOD) % MOD;
                    ll tem = r * (r + 1) % MOD * (2 * r + 1) % MOD * inv6 % MOD;
                    ll tem2 = (l - 1) * l % MOD * (2 * l - 1) % MOD * inv6 % MOD;
                    ans -= v * (tem - tem2 + MOD) % MOD;
                    ans = (ans + MOD) % MOD;
                    ans += v * cnt % MOD;
                    ans %= MOD;
                }
            };
            check();
            break;
        }
    }
    cout << ans << endl;
    return;
}