惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Y
Y Combinator Blog
腾讯CDC
Recent Announcements
Recent Announcements
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Hugging Face - Blog
Hugging Face - Blog
H
Help Net Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Last Week in AI
Last Week in AI
博客园_首页
D
DataBreaches.Net
P
Proofpoint News Feed
云风的 BLOG
云风的 BLOG
V
Visual Studio Blog
月光博客
月光博客
Jina AI
Jina AI
Stack Overflow Blog
Stack Overflow Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 【当耐特】
Vercel News
Vercel News
WordPress大学
WordPress大学
J
Java Code Geeks
博客园 - 聂微东
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
U
Unit 42

Shiroha白羽的博客

Golang 踩坑 —— interface 为参数的时候传 nil 指针 Codeforces Round 925 (Div. 3) Codeforces Round 924 (Div. 2) Codeforces Round 923 (Div. 3) Codeforces Round 922 (Div. 2) Codeforces Round 921 (Div. 2) Educational Codeforces Round 161 (Rated for Div. 2) Codeforces Round 920 (Div. 3) Codeforces Round 919 (Div. 2) Hello 2024 Good Bye 2023 Codeforces Round 918 (Div. 4) 个人备份的常用 macOS 清理命令 Codeforces Round 917 (Div. 2) Pinely Round 3 (Div. 1 + Div. 2) Educational Codeforces Round 160 (Rated for Div. 2) Codeforces Round 915 (Div. 2) Codeforces Round 914 (Div. 2) Codeforces Round 913 (Div. 3) Educational Codeforces Round 159 (Rated for Div. 2) Codeforces Round 912 (Div. 2) Codeforces Round 911 (Div. 2) CodeTON Round 7 (Div. 1 + Div. 2, Rated, Prizes!) Educational Codeforces Round 158 (Rated for Div. 2) Codeforces Round 910 (Div. 2) Codeforces Round 909 (Div. 3) Codeforces Round 908 (Div. 2) Educational Codeforces Round 157 (Rated for Div. 2) C++自定义的字面量 Codeforces Round 907 (Div. 2)
Codeforces Round 897 (Div. 2)
Shiroha · 2023-09-16 · via Shiroha白羽的博客

A. green_gold_dog, array and permutation

大致题意

已知一个数组 $a$,长度为 $n$,需要给出一个 $n$ 的排列 $b$,使得得到的新数组 $c_i = a_i - b_i$ 中不同的值尽可能多,问数组 $b$ 的结果可能是

思路

简单来说就是要差值差异大,而且没有取 $abs$,所以可以直接排序一下,一个递增一个递减配对即可

AC code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void solve() {
int _;
cin >> _;
for (int ts = 0; ts < _; ++ts) {
int n;
cin >> n;
vector<pair<int, int>> data(n);
for (auto &item: data) cin >> item.first;
for (int i = 0; i < n; ++i) data[i].second = i;
sort(data.begin(), data.end(), greater<>());
for (int i = 0; i < n; ++i) data[i].first = i + 1;
sort(data.begin(), data.end(), [](const pair<int, int> &lhs, const pair<int, int> &rhs) {
return lhs.second < rhs.second;
});
for (int i = 0; i < n; ++i) cout << data[i].first << " \n"[i == n - 1];
}
}

B. XOR Palindromes

大致题意

已经存在一个二进制的字符串 $a$,长度为 $n$,若存在另外一个字符串 $b$,其长度也为 $n$,其中 1 的数量恰好为 $x$,使得 $a \oplus b$ 恰好是一个回文串。则称 $x$ 是一个好值,问在 $[0, n]$ 中哪些值是好值

思路

首先,在异或操作中,若其中一方为 1 已知,那么相当于对对方进行了翻转操作。

而要回文串,那么必然可以将初始串先按位分割,只看左右的其中一半,若这个位置本来就会回文(和后半对应的位置相同),那么需要寻找的串必定这两位要相同,否则必须不同,由此可以计算出至少要 1 的数量和最多能够用上的 1 的数量。

另外关注字符串本身是否是奇数长度的,这样意味着如果恰好多一个,就可以放到中间解决问题,如果不是的话,那么满足条件的值会间隔开

AC code

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
void solve() {
int _;
cin >> _;
for (int ts = 0; ts < _; ++ts) {
int n;
cin >> n;
string str;
cin >> str;
str.reserve(n);
int diff = 0, same = 0;
for (int i = 0; i < (n + 1) / 2; ++i) {
diff += str[i] != str[n - 1 - i];
same += str[i] == str[n - 1 - i];
}
for (int i = 0; i <= n; ++i) {
if (i < diff || i > n - diff) cout << 0;
else if (n % 2) cout << 1;
else {
if ((i - diff) % 2 == 0) cout << 1;
else cout << 0;
}
}
cout << endl;
}
}

C. Salyg1n and the MEX Game

交互题(这场交互题真多)

大致题意

有一个初始的集合,里面有一些值,你可以每次往里面加一个不存在的值,然后机器会每次往里面删除一个存在的值,且每次删除的值一定比你加入的值小。如果无法删除值了(没有满足条件的值了)那么就结束,问如何使得 MEX 最大化

思路

实际上对于删除方,第一优先级的肯定是删除掉最小的值,因为只有这样能最有效的降低 MEX

对于你而言,一旦试图添加 0 这种最低值的时候,游戏就会结束,此时 MEX 就取决于往后的第一个空档。可以发现一旦被删除掉的值是最小的,那么就再也不能救回比那个值更小的可能性了。而因为最终一次操作一定是加入的,所以只需要对方删除啥你就加入什么即可,保证不要被删掉小的值。而第一次加入,就可以选择当前的 MEX,来增加最终的 MEX 的结果

题非常简单易懂,但是解释起来又有些难

AC code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void solve() {
int _;
cin >> _;
for (int ts = 0; ts < _; ++ts) {
int n;
cin >> n;
vector<int> data(n);
for (auto &item: data) cin >> item;
sort(data.begin(), data.end());
int mex = n;
for (int i = 0; i < n; ++i)
if (data[i] != i) {
mex = i;
break;
}
cout << mex << endl;
cout.flush();
while (cin >> mex && mex != -1) {
cout << mex << endl;
cout.flush();
}
}
}

D. Cyclic Operations

大致题意

有一个初始每一个值都是 0 的数组 $a$,长度为 $n$,希望变成目标数组 $b$,可以进行如下操作

  • 构造任意一个长度恰好为 $k$ 的数组 $c$,$k$ 为给出的固定数字
  • $\forall i \in [1, k], a_{l_i} \rightarrow l_{(i \space mod \space k) + 1}$

允许进行无数次操作,问是否有可能变成 $b$

思路

首先仔细模拟一下这个看起来很恐怖的公式,发现其实就是 $a_{l_i} \rightarrow l_{i+1}$ 注意这里可以看成是循环数组,否则会越界

然后考虑一下特殊情况,就是 $k = 1$ 的情况,这个时候必须每个值的下标等于自己,否则肯定不行,这里就不过多解释了,模拟一下就行。

然后是其他情况下,模拟一下就会发现有点类似有向图一样,而且比较显而易见必然会产生环

所以只需要让有向图上的环的大小都恰好等于 $k$ 即可,对于分支链路,他们可以直接临时占用环的一部分,而后通过环本身将其覆盖即可

AC code

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
void solve() {
int _;
cin >> _;
for (int ts = 0; ts < _; ++ts) {
int n, k;
cin >> n >> k;
vector<int> data(n);
vector<int> circle(n, 0);
vector<int> level(n, 0);
for (auto &item: data) cin >> item;
if (k == 1) {
bool flag = true;
for (int i = 0; i < n; ++i) if (data[i] != i + 1) flag = false;
cout << (flag ? "YES" : "NO") << endl;
continue;
}

bool flag = true;
int cur = 1;
for (int i = 0; i < n; ++i) {
if (circle[i] != 0) continue;
cur++;
int len = 0, index = i;
while (circle[index] == 0) {
circle[index] = cur;
level[index] = len++;
index = data[index] - 1;
}
if (circle[index] != cur) {
// other circle, no matter how len it is, always OK
continue;
}
if (len - level[index] != k) {
flag = false;
break;
}
}
cout << (flag ? "YES" : "NO") << endl;
}
}

E2. Salyg1n and Array (hard version)

easy version 要求更低,所以直接做 hard

大致题意

有一个未知的数组,长度为 $n$,需要求出整个数组的异或和是多少

每次可以询问一个区间的异或和,这个区间长度一定为给定的 $k$,询问后,整个区间将会翻转

最多只能请求 57 次

思路

很显然,可以知道至多 $50$ 就可以保证覆盖到所有的区间,如果恰好 $k$ 是 $n$ 的因子,那么就可以恰好满覆盖,循环一遍直接可以得到答案了

如果不满足的情况,就需要考虑一种方案了,这里给出我的一个方案,接下来会参考下面的图进行讲解,图中,$a, b$ 两段之和(蓝色部分)是不满足完美分配后,余下的部分,其他的黑色部分则是可以完美分配的部分,其中 $len(a) = len(b) = len(d) = len(e)$(注意题目中描述了 $n, k$ 必定都是偶数,所以肯定可以这样分配),同时 $len(a) + len(b) + len(c) + len(d) = k$,且 同时 $len(b) + len(c) + len(d) + len(e) = k$

E2

先要求算出 $a,b,c,d$ 这个区间的异或和,假设记为 $x$,如此操作后,必定迎来翻转操作,即区间变成 $d, (c+b), a, e$ 的顺序,其中因为 $c$ 区间长度不确定,故和 $b$ 放在一块,不做区分。

然后再计算 $(c+b), a, e$ 的区间异或和,得到 $y$,同时翻转后得到 $d, e | (a+b+c)$,此处同理,此时无法完美区分 (a+b+c) 的区间长度到底是多少,只是大概知道个顺序罢了,因为我们也不关心顺序,故合并起来写,注意中间的其,其表示原来图中的蓝色和黑色部分的分割线。第一次翻转后,这根线无法进行绘制故没有标出,此时可以标出了

接着计算 $x \oplus y = (a \oplus b \oplus c \oplus d) \oplus (c \oplus b \oplus a \oplus e) = d \oplus e$,这不是正好是翻转后的外面部分的,那么问题好像就解决了

AC code

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
void solve() {
int _;
cin >> _;
for (int ts = 0; ts < _; ++ts) {
int n, k, ans = 0, tmp;
cin >> n >> k;
if (n % k != 0) {
int len = n % k;
cout << "? 1" << endl;
cout.flush();
cin >> tmp;
ans ^= tmp;
cout << "? " << (len / 2 + 1) << endl;
cout.flush();
cin >> tmp;
ans ^= tmp;
}
for (int i = n % k; i < n; i += k) {
cout << "? " << i + 1 << endl;
cout.flush();
cin >> tmp;
ans ^= tmp;
}
cout << "! " << ans << endl;
}
}