A. Lame King
给出一张大小为201 * 201的图,问从(0, 0)到(a, b)最少需要多少步,每一步可以选择上下左右和不走,相连的两步不能向同一个方向。
思路:很显然,两数绝对值相差在1之内就可以直接相加;否则,对于多出来的部分,可以一走一停到达。
AC Code:
#include <bits/stdc++.h>
typedef long long ll;
const int N = 1e5 + 5;
int t, a, b;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin >> t;
while(t --) {
std::cin >> a >> b;
a = std::max(a, -a);
b = std::max(b, -b);
if(abs(a - b) <= 1) {
std::cout << a + b << '\n';
continue;
}
int max = std::max(a, b);
int min = std::min(a, b);
int ans = 2 * min + 1;
max -= min + 1;
ans += max * 2;
std::cout << ans << '\n';
}
return 0;
}
B. Vaccination
一个疫苗袋子里有k支疫苗,一个患者最多等w时间,疫苗开封后最多能用d时间,有n个患者。给出患者来的时间,假设防疫站有足够的工作人员进行任何数量的操作,求最少需要开封多少袋疫苗。
思路:为了尽可能减少疫苗开袋,对于时间来的前后的患者,可以让他们等待不超过w时间,使得前后的患者可以使用同一袋疫苗。模拟这个过程即可。
AC Code:
#include <bits/stdc++.h>
typedef long long ll;
const int N = 2e5 + 5;
ll t, n, k, d, w;
ll a[N];
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin >> t;
while(t --) {
std::cin >> n >> k >> d >> w;
for(int i = 1; i <= n; i ++) {
std::cin >> a[i];
}
int st = a[1], cnt = k - 1, ans = 1;
bool flag = false;
for(int i = 2; i <= n; i ++) {
if(a[i] - st > d && cnt) {
if(st + d + w >= a[i] && !flag) {
st += w;
flag = true;
cnt --;
}
else
ans ++, st = a[i], cnt = k - 1, flag = false;
}
else if(!cnt)
ans ++, st = a[i], cnt = k - 1, flag = false;
else
cnt --;
}
std::cout << ans << '\n';
}
return 0;
}
C. Pull Your Luck
给出n个盘块,编号0~n -1,第0号与n - 1号相连。现在位于编号为x的位置,选择1~p的一个数,使得扇区转动(1 + k) * k / 2块,计算能否通过一次旋转使得盘块停留在0号位置。
思路:很容易想到在p这么大的范围内一定有对n取模相等的数。设转动的数字为k,那最后要判断的就是对于任意一个k,((1 + k) * k / 2 % n + x) % n是否等于0。所以主要决定作用来自于这个求等差数列和的位置,而对于1~2*n位置的和,(1 + 2 * n) * n是n的倍数,继续向后的2 * n + 1而言,会重复前面的求和对n取余的余数,所以将问题转化为在1~min(2 * n, p)内找到这个满足条件的数字,降低了时间复杂度,能过。
AC Code:
#include <bits/stdc++.h>
typedef long long ll;
const int N = 2e5 + 5;
ll t, n, x, p;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin >> t;
while(t --) {
std::cin >> n >> x >> p;
bool flag = false;
ll res;
for(ll i = 1; i <= std::min(2 * n, p); i ++) {
res = (((1 + i) * i / 2) % n + x % n) % n;
if(res == 0) {
flag = true;
break;
}
}
std::cout << (flag ? "Yes" : "No") << '\n';
}
return 0;
}
D. Accommodation
对于一层楼上,一共有m盏灯,有一盏灯的屋子m / 2间和两盏灯的屋子m / 4间,给出每一层楼灯的明灭情况,现在不知每一层楼两种屋子的分布情况,求有亮灯的屋子最少和最多有多少间。
思路:对于最少的时候,就是尽可能使两盏灯的屋子中两盏灯全亮;对于最多的时候,就是尽可能使得每一盏灯都分到一个屋子。对于最少的情况,比较容易实现;最多的情况,我们可以反向考虑,计算有多少间两盏灯的屋子两盏灯必须都亮,那用灯的数量减去这些数量就是亮灯房间的个数。
AC Code:
#include <bits/stdc++.h>
typedef long long ll;
#define int long long
const int N = 2e5 + 5;
int n, m;
std::string s;
signed main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin >> n >> m;
int max = 0, min = 0;
while(n --) {
std::cin >> s;
s = ' ' + s;
int cnt = 0;
int cnt1 = std::count(s.begin(), s.end(), '1');
for(int i = 1; i <= m; i ++) {
if(s[i] == '0') continue;
if(i < m && s[i + 1] == '1')
cnt ++, i ++;
}
min += cnt1 - std::min(m / 4, cnt);
cnt = 0;
for(int i = 1; i <= m; i ++) {
if(i < m && (s[i] != s[i + 1] || s[i] == '0'))
cnt ++, i ++;
}
if(cnt <= m / 4)
max += cnt1 - (m / 4 - cnt);
else
max += cnt1;
}
std::cout << min << ' ' << max << '\n';
return 0;
}