Featured image of post Codeforces Round #1004(Div.1)

Codeforces Round #1004(Div.1)

Div.2 B

题目大意:你有两个装数字的大袋子。初始时,第一个袋子包含 $n$ 个数字:$a_1, a_2, \ldots, a_n$,而第二个袋子为空。你可以执行以下两种操作: - 从第一个袋子中选择任意数字移动到第二个袋子。- 从第一个袋子中选择一个同时在第二个袋子中存在的数字,并将其增加一。你可以以任意顺序执行无限次上述两种操作。是否可能使两个袋子的内容完全相同?

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

思路:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
void solve() {
    int n;
    cin >> n;
    vi a(n);
    rep(i, 0, n - 1) cin >> a[i];
    vi cnt(n + 1);
    rep(i, 0, n - 1) cnt[a[i]]++;
    int las = 0;
    rep(i, 1, n) {
        if (cnt[i] == 1) {
            cout << "No" << endl;
            return;
        }
        if (cnt[i] == 0) continue;
        if (i != n) cnt[i + 1] += cnt[i] - 2;
    }
    cout << "Yes" << endl;
    return;
}

Div.2 C

题目大意:给定一个正整数 $n$。每次操作,你可以向 $n$ 加上任意一个仅由数字 $9$ 组成的正整数(可以有多个 $9$)。问最少需要多少次操作,才能使 $n$ 的十进制表示中至少包含一个数字 $7$。

数据范围:$1 \leq t \leq 10^4$,$10 \leq n \leq 10^9$。

思路:

 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
void solve() {
    ll n;
    cin >> n;
    auto check = [&](ll x) -> bool {
        while (x > 0) {
            if (x % 10 == 7) return true;
            x = x / 10;
        }
        return false;
    };
    if (check(n)) {
        cout << 0 << endl;
        return;
    }
    vl cnt(10);
    cnt[0] = 9;
    rep(i, 1, 9) { cnt[i] = cnt[i - 1] * 10 + 9; }
    rep(i, 1, 9) {
        rep(j, 0, 9) {
            ll tem = n;
            if (check(tem + cnt[j] * i)) {
                cout << i << endl;
                return;
            }
        }
    }
    return;
}

Div.1 A

题目大意:这是一道交互题。给定一个由 $1$ 到 $n$ 的整数构成的数组 $x_1, \ldots, x_n$。评测方还拥有一个固定但隐藏的数组 $y_1, \ldots, y_n$,其元素也是 $1$ 到 $n$ 的整数。数组 $y$ 的元素对你未知。此外,已知对于所有 $i$,$x_i \neq y_i$,且所有有序对 $(x_i, y_i)$ 互不相同。评测方秘密选择了以下两个对象之一,需要判断具体是哪一个: - 对象 A:一个包含 $n$ 个顶点(编号为 $1$ 到 $n$)的有向图,包含 $n$ 条形如 $x_i \to y_i$ 的边。

数据范围:$1 \le t \le 1000$。

思路:

 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
int ask(int l, int r) {
    int op;
    cout << "? " << l << ' ' << r << '\n';
    cout.flush();
    cin >> op;
    return op;
}
void report(char sum) {
    cout << "! " << sum << '\n';
    cout.flush();
}
void solve() {
    int n;
    cin >> n;
    vi a(n);
    rep(i, 0, n - 1) {
        cin >> a[i];
        a[i]--;
    }
    vi cnt(n, -1);
    rep(i, 0, n - 1) { cnt[a[i]] = i; }
    int idx = -1;
    rep(i, 0, n - 1) {
        if (cnt[i] == -1) {
            idx = i;
            break;
        }
    }
    if (idx != -1) {
        int idx2 = -1;
        rep(i, 0, n - 1) {
            if (i == idx) continue;
            idx2 = i;
            break;
        }
        int op = ask(idx + 1, idx2 + 1);
        if (op == 0)
            report('A');
        else
            report('B');
        return;
    }
    int op = ask(cnt[0] + 1, cnt[n - 1] + 1);
    int op2 = ask(cnt[n - 1] + 1, cnt[0] + 1);
    if (op + op2 > n)
        report('B');
    else
        report('A');
    return;
}

Div.1 B

题目大意:我们称一个序列 $a_1, a_2, \ldots, a_n$ 是魔法的,如果对于所有 $1 \leq i \leq n-1$ 满足:$\operatorname{min}(a_1, \ldots, a_i) \geq \operatorname{mex}(a_{i+1}, \ldots, a_n)$。特别地,任意长度为 $1$ 的序列都被视为魔法序列。一个整数集合 $a_1, a_2, \ldots, a_k$ 的最小未出现值(MEX)被定义为未出现在该集合中的最小非负整数 $t$。给定一个由 $n$ 个非负整数构成的序列 $a$。请找到该序列的魔法子序列$^{\text{∗}}$ 的最大可能长度。

数据范围:$1 \le t \le 10^4$,$1 \leq n \leq 2 \cdot 10^5$,$0 \leq a_i \leq 10^9$,$\sum n \le 2 \cdot 10^5$。

思路:

 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
void solve() {
    int n;
    cin >> n;
    vl a(n);
    rep(i, 0, n - 1) cin >> a[i];
    int idx = -1;
    rep(i, 0, n - 1) {
        if (a[i] == 0) {
            idx = i;
            break;
        }
    }
    if (idx == -1) {
        cout << n << endl;
        return;
    }
    int tot = 0;
    rep(i, 0, n - 1) tot += (a[i] > 0);
    vi suf(n);
    vi vis(n + 2);
    vis[0] = 1;
    int cnt = 1;
    frep(i, n - 1, 0) {
        suf[i] = cnt;
        if (a[i] > 0 && a[i] <= n) {
            vis[a[i]] = 1;
            while (vis[cnt]) cnt++;
        }
    }
    ll mixx = INT_MAX;
    bool flag = true;
    bool flag2 = false;
    rep(i, 0, n - 1) {
        if (a[i] == 0) {
            if (flag) flag2 = true;
        } else {
            mixx = min(mixx, a[i]);
            if (mixx < suf[i]) flag = false;
        }
    }
    cout << tot + flag2 << endl;
    return;
}

Div.1 C

题目大意:给定一个数组 $a_1, a_2, \ldots, a_n$,以及三个初始值为零的变量 $P, Q, R$。需要按从 $1$ 到 $n$ 的顺序依次处理所有数字 $a_1, a_2, \ldots, a_n$。当处理当前元素 $a_i$ 时,你必须从以下三个操作中任选一个执行: 1. $P := P \oplus a_i$ 2. $Q := Q \oplus a_i$ 3. $R := R \oplus a_i$ 其中 $\oplus$ 表示按位异或操作。执行操作时必须遵守核心规则:每次操作后,三个数 $P, Q, R$ 必须满足其中至少存在两个数相等。所有 $n$ 个操作共有 $3^n$ 种可能的执行方式。求其中不违反核心规则的方式数量。

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

思路:

 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
const ll MOD = 1e9 + 7;
ull splitmix64(ull x) {
    x += 0x9e3779b97f4a7c15;
    x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
    x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
    return x ^ (x >> 31);
}

struct custom_hash {
    static const ull FIXED_RANDOM;

    size_t operator()(ull x) const { return splitmix64(x + FIXED_RANDOM); }
};

const ull custom_hash::FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
// 如果是 x x x^d 那么,此时异或一个 d 有三种情况
void solve() {
    int n;
    cin >> n;
    vl a(n);
    rep(i, 0, n - 1) cin >> a[i];
    umap<ll, ll, custom_hash> ma;
    ma[0] = 1;
    ll tem = 0;
    ll ans = 1;
    rep(i, 0, n - 1) {
        ll tem2 = a[i];
        ll tem3 = 2 * (ma[tem] + ma[tem ^ tem2]) % MOD;
        ma[tem] = (ma[tem] + tem3) % MOD;
        tem ^= tem2;
        ans = (ans + tem3) % MOD;
    }
    cout << ans << endl;
    return;
}

Div.1 D1

题目大意:这是该问题的简单版本。各版本间的区别在于此版本中所有 $a_i = 0$。只有当您解决了该问题的所有版本时才能进行 hack。有一栋 $n$ 层的建筑物,楼层从下到上编号为 $1$ 至 $n$。每层恰好住着一位居民。今天全体居民有一个重要目标:共同发射至少 $c$ 架纸飞机。居民们将依次发射飞机。当第 $i$ 层的居民发射一架飞机时,从第 $1$ 层到第 $i$ 层的所有居民都能看到它降落到地面的过程。如果从第 $i$ 层居民的视角看,已有至少 $c$ 架飞机被发射,则该居民自己不会再发射更多飞机。已知到当天结束时,从每位居民的视角看至少发射了 $c$ 架飞机,且总共发射了 $m$ 架飞机。您仔细记录了这次快闪活动,记录了每位发射飞机的居民所在楼层。

数据范围:$1 \le t \le 10^4$,$1 \le n \le 100$,$1 \le c \le 100$,$c \le m \le n \cdot c$,$0 \le a_i \le n$,$\sum m \le 10^4$。

思路:

 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
constexpr int MOD = 1e9 + 7;
constexpr int MX = 1e5 + 1;
ll F[MX];      // 预处理阶乘
ll INV_F[MX];  // 预处理逆元
ll qpow(ll x, int n) {
    ll res = 1;
    for (; n; n >>= 1) {
        if (n % 2) res = res * x % MOD;
        x = x * x % MOD;
    }
    return res;
}
auto init = [] {
    F[0] = 1;
    for (int i = 1; i < MX; i++) F[i] = F[i - 1] * i % MOD;  // 预处理阶乘
    INV_F[MX - 1] = qpow(F[MX - 1], MOD - 2);
    for (int i = MX - 1; i; i--) {
        INV_F[i - 1] = INV_F[i] * i % MOD;
    }  // 预处理逆元
    return 0;
}();
// 计算C(n,m),即从n个数中取m个数
ll comb(int n, int m) { return m < 0 || m > n ? 0 : F[n] * INV_F[m] % MOD * INV_F[n - m] % MOD; }
void solve() {
    ll n, c, m;
    cin >> n >> c >> m;
    vl a(m);
    rep(i, 0, m - 1) cin >> a[i];
    cout << comb(c * (n - 1), m - c) << endl;
    return;
}