Codeforces Round 996 (Div. 2)
https://codeforces.com/contest/2055
A. Two Frogs
题意:有一排莲叶,1~n,两个青蛙 A 和 B ,起初分别位于 a 和 b,每一个回合可以向左向右跳一格,前提是这个莲叶上没有青蛙。当一个青蛙不能跳了,它就输了。A 先跳,A 能赢吗?
题解:A 和 B 分别跳一个回合,他们之间的距离的奇偶性不会改变。最后 A 和 B 之间的距离为 0,并且轮到 A 的回合了,那么 A 就输了。反之 B 输。递推到距离为 2,还是 A 输。所以当距离为偶数就是 A 输。
void slove() {
int n, a, b; cin >> n >> a >> b;
int c = abs(a - b) - 1;
if (c & 1) {
cout << "YES" << endl;
} else {
cout << "NO" << endl;
}
}
B. Crafting
题意:给定两个数组 a, b,长度都为 n。在数组 a 可以选择一个元素 i,使得 \(a_i:=a_i + 1\) ,其它所有元素,\(j \in [1, n] \and j \neq i\ \and a_j \geq 1,\ a_j := a_j - 1\) 。可以操作任意次,最后能否使得 a 的每一个都至少为 b。
题解:对于一个位置 \(a_i < b_i\) ,那么这个位置就需要操作,累加 1 的话,a 的总和要减小 n - 1。如果有两个位置 \(a_i < b_i, a_j < b_j\) ,那么无论如果都不能使得 a 变成 b,因为一个位置增加多少,另外一个位置就需要减少多少。所以最多只能有一个位置比 b 小。并且其它位置增量都必须大于等于这个差值。
void slove() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = 1; i <= n; i++) {
cin >> b[i];
}
int cnt = 0;
int c = 0, minv = 1e9;
for (int i = 1; i <= n; i++) {
if (a[i] < b[i]) {
cnt++;
c = b[i] - a[i];
} else {
minv = min(minv, a[i] - b[i]);
}
if (cnt >= 2) {
cout << "NO" << endl;
return;
}
}
if (minv >= c) {
cout << "YES" << endl;
} else {
cout << "NO" << endl;
}
}
C. The Trail
题意:给定一个 \(n\times m\) 的矩阵,给定一条路径,只有 D 和 R 字符组成,D 表示向下一格,R 表示向右一格。起点为 \((1, 1)\) 终点为 \((n, m)\) 。那么路径的长度为 \(n+m-2\)。路径对应矩阵上值为 0,要求填充路径对应的格点,使得每一行和每一列都相等。
题解:设一行或一列的和为 sum,那么整个矩阵的和可以表示为:\(n\times sum\) 或者 \(m\times sum\), 那么存在关系:\(n\times sum=m\times sum\) 。\(n\neq m \Rightarrow sum=0, \ n=m\Rightarrow sum \in R\) .
如果依次填充的,每一步都可以找到一行或一列只差一个空位没有填充。不妨直接使得这一行或这一列为 0。
void slove() {
cin >> n >> m;
string s; cin >> s;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> a[i][j];
}
}
int x = 1, y = 1;
for (char c : s) {
if (c == 'D') {
LL sum = 0;
for (int i = 1; i <= m; i++) {
sum += a[x][i];
}
a[x][y] = -sum;
x++;
} else {
LL sum = 0;
for (int i = 1; i <= n; i++) {
sum += a[i][y];
}
a[x][y] = -sum;
y++;
}
}
LL sum = 0;
for (int i = 1; i <= m; i++) {
sum += a[x][i];
}
a[x][y] = -sum;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cout << a[i][j] << " ";
}
cout << endl;
}
}
D. Scarecrow
题意:给定一个数组表示稻草人的初始位置,有一只乌鸦起初位于 0,稻草人可以以每秒一个单位的速度向左右移动。每当存在稻草人位于乌鸦的位置或者乌鸦的左边,使得二者距离小于 k,乌鸦就会瞬间移动到稻草人的右边距离 k。比如:存在一个稻草人位于 y 处,一个乌鸦位于 x 处。\(y\leq x\), 如果 \(x-y < k\) ,那么乌鸦就会从 x 移动到 \(y+k\) 。最后使得乌鸦的位置大于等于 L,至少需要多少时间,输出时间的2倍。
题解:输出时间的2倍,是考虑精度,1 秒移动 1 格,可以 0.5 秒移动半格。全局乘 2 即可。
起初肯定需要第一个稻草人移动到 0 的位置,使得乌鸦处于 k 处。记录全局需要的时间,以及乌鸦当前的位置。
从第二个稻草人开始,依次处理每一个稻草人。稻草人的位置 \(a_i\), 乌鸦当前的位置 \(pos\) 。
- \(pos \geq a_i\) ,乌鸦位于这个稻草人的右边,那么现在 i 的左边的稻草人都无用了。只需要考虑 i 这个稻草人即可。首先可以移动到 \(min(a_i+time, pos)\) ,乌鸦可以移动到哪里呢?\(min(a_i+time, pos) + k\) 。当前位于 pos 位置是被 i-1 位置的稻草人赶过来的,\(pos-a_{i-1} \geq k\) ,\(pos \geq a_i \geq a_{i-1}\) 。\(a_i+time\) 是目前第 i 个稻草人最远可以移动的位置,必然不小于第 i-1 个稻草人最远可以移动的位置。那么第 i 个稻草人最多可以使得乌鸦移动到 \(min(a_i+time, pos) + k\) 肯定比前面的稻草人更远。
- \(pos<a_i\)。这种情况下,乌鸦位于第 i 个稻草人和第 i - 1 个稻草人之间。且 \(pos-a_{i-1} \geq k\) 。那么最优的决策是,两个稻草人往中间移动,第 i-1 个稻草人每向右移动一格,就会使得乌鸦往右移动一格。同时第 i 个稻草人往左移动一格,会使得乌鸦和第 i 个稻草人之间的距离缩减 2 格。0.5 秒的话,就缩减 1 格,这也是为什么会出现移动 0.5 秒的原因。此时消耗的时间就是 \(\frac{(a_i-pos)}{2}\) 。乌鸦移动 \(\frac{a_i-pos}{2}+k\) 。
void slove() {
cin >> n >> k >> l;
k *= 2, l *= 2;
for (int i = 1; i <= n; i++) {
cin >> a[i];
a[i] *= 2;
}
int res = a[1], pos = k;
for (int i = 2; i <= n; i++) {
if (pos >= a[i]) {
a[i] = min(a[i] + res, pos);
pos = a[i] + k;
} else {
a[i] = max(a[i] - res, pos);
int t = (a[i] - pos) / 2;
pos += t + k;
res += t;
}
}
if (pos < l) {
res += l - pos;
}
cout << res << endl;
}
浙公网安备 33010602011771号