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;
}
|