「题解」Codeforces Round 994 (Div.2)
A. MEX Destruction
龙 Evirir 溜进了巫师的城堡,发现了一个神秘的装置,他们贪玩的本能让他们玩弄(毁坏)了它......
埃维里尔龙发现了一个由 个非负整数组成的数组 。
在一次操作中,他们可以选择一个非空的子数组 。 的子数组 ,并将其替换为整数 。他们想多次使用这种运算使 只包含零。可以证明,在问题的限制条件下,这总是可行的。
所需的最少运算次数是多少?
一个数组 是一个数组 的子数组,如果 可以从 中通过删除开头的几个(可能是零或全部)元素和结尾的几个(可能是零或全部)元素得到。
整数集合 的最小排除数(MEX)定义为在集合 中不出现的最小非负整数 。
看起来有点神秘。看数据范围以为是暴力,仔细观察样例答案只有 ,三种情况。于是写出代码:
void solve() {
int n;
cin >> n;
vector a(n, 0);
for (auto &x : a)
cin >> x;
int cnt = 0;
vector<int> z;
bool nz = false;
for (int i = 0; i < a.size(); i ++) {
if (a[i] == 0) {
if (nz)
cnt ++;
nz = false;
continue;
}
nz = true;
}
if (nz)
cnt ++;
if (cnt == 0)
cout << 0;
else if (cnt == 1)
cout << 1;
else
cout << 2;
cout << "\n";
}遂 AC。
但现在是考后写题解的时候,因此我们有必要好好地证明一下。
考虑到我们要让这个 变成一个全 的数组,我们唯一可以的操作就是选择一个子数组(连续)使得这个数组变成一个单独的 ,求最小的操作次数。
一般的,当这个数组全由 组成的时候,操作数为 ; 此外,当一个数组不包含 ,的时候,这个数组的 为 。
我们假设这个原数组是由正整数组成的数组,由上性质可知经过一次操作就能完成。
那如果这个数组中存在 呢?我们经过一次操作就能使得这个数组变成一个正整数,然后再当成一个正整数数组处理即可(两步操作),这是可能发生的操作次数最多的情况。
也就是说,当数组 全为 时,答案为 ;当数组全为正整数的时候,答案为 ;其他情况答案为 。
不知道为什么我答案写得那么别扭
原代码中相当于往数组的最后添加一个 ,cnt 统计的就是被 分割的段数。根据我们已知的结论输出答案即可(段数为 相当于全是正整数)。
B. pspspsps
Cats are attracted to pspspsps, but Evirir, being a dignified dragon, is only attracted to pspspsps with oddly specific requirements...
Given a string of length consisting of characters p, s, and . (dot), determine whether a permutation of length exists, such that for all integers ():
- If is p, then forms a permutation (of length );
- If is s, then forms a permutation (of length );
- If is ., then there is no additional restriction.
A permutation of length is an array consisting of distinct integers from to in arbitrary order. For example, is a permutation, but is not a permutation ( appears twice in the array), and is also not a permutation ( but there is in the array).
翻译后公式抽风了就不放翻译了。
这个题目写的语焉不详的,简单来说就是对于字符 p,要求我们构造的排列能满足 ,(其中 代表字符的位置,下同)是一个排列;对于字符 s 要求 也是一个排列。
我们首先考虑字符串中顺序出现的 p,假如 是一个排列,那么我们一定能构造一个排列 ,所以我们能做到从第一个出现的 p 生成的排列上不断添油让最后一个位置的 p 也能满足题设。因此我们只考虑最后一个 p 的位置即可。同理可得,对于 s,我们只需要关注第一个的位置即可。
有且仅有如下三种情况能满足题设:
- 仅存在
s; - 仅存在
p; - 某一个的排列区间包含于另外一个的排列区间。
对于 s,这个区间是 ,而对于 p,这个区间是 ;因此第三个条件等同于 或者 。
我们扫一遍字符串即可(代码略)
C. MEX Cycle
Evirir the dragon has many friends. They have 3 friends! That is one more than the average dragon.
You are given integers , , and . There are dragons sitting in a circle. The dragons are numbered . For each (), dragon is friends with dragon and , where dragon is defined to be dragon and dragon is defined to be dragon . Additionally, dragons and are friends with each other (if they are already friends, this changes nothing). Note that all friendships are mutual.
Output non-negative integers such that for each dragon (), the following holds:
- Let be the friends of dragon . Then .
The minimum excluded (MEX) of a collection of integers is defined as the smallest non-negative integer which does not occur in the collection .
可以把龙之间的朋友关系看作一个图,要求对于点 ,其对应的值 ,其中 代表与 相邻的点。
感觉认真的考虑这个问题对我来说可能有点困难。但不难注意到一个龙最多只能有 个好友,至少也有 个好友。同时这个图肯定存在一个环。所以我们可以多跑几遍暴力算法直到每一个元素都满足题设即可。
inline int mex(set<int> &x) {
for (int i = 0; i <= inf; i ++) {
if (!x.count(i))
return i;
}
return 0;
}
void solve() {
int n, x, y;
cin >> n >> x >> y;
vector vec(n + 1, set<int>());
vector a(n + 1, 0ll);
vec[x].insert(y); vec[y].insert(x);
for (int i = 1; i <= n; i ++) {
int a = i % n + 1, b = (n + i - 2) % n + 1;
vec[i].insert(a); vec[i].insert(b);
vec[a].insert(i); vec[b].insert(i);
}
bool ok = false;
ok = true;
for (int i = 1; i <= n; i ++) {
set<int> tmp;
for (auto &v : vec[i])
tmp.insert(a[v]);
if (a[i] != mex(tmp))
ok = false;
a[i] = mex(tmp);
}
for (int i = 1; i <= n; i ++)
cout << a[i] << " ";
cout << "\n";
}D.
const int inf = 1e18;
void solve() {
int n, m, k;
cin >> n >> m >> k;
vector a(n + 1, vector(m, 0ll));
for (int i = 1; i <= n; i ++) {
for (int j = 0; j < m; j ++)
cin >> a[i][j];
}
vector f(n + 1, vector(m + 1, inf));
f[0][0] = 0;
for (int i = 1; i <= n; i ++) {
for (int x = 0; x < m; x ++) {
vector g(m, inf);
for(int j = 0; j < m; j ++)
g[j] = f[i - 1][j] + a[i][(j + x) % m] + k * x;
for (int j = 0; j < m; j ++)
g[j] = min(g[j], g[(j + m - 1) % m] + a[i][(j + x) % m]);
for (int j = 0; j < m; j ++)
f[i][j] = min(f[i][j], g[j]);
}
}
cout << f[n][m - 1] << endl;
}如上。