牛客周赛 Round 83
A. 和猫猫一起起舞!
点击查看代码
void solve() {
std::string s;
std::cin >> s;
if (s == "U" || s == "D") {
std::cout << "L\n";
} else {
std::cout << "U\n";
}
}
B. 冒险猫猫参上!!
题意:构造一个数组,使得\(\forall i \in [1, n - 1], |a_i - a_{i+1}| = 1\),且总和不超过\(3 \times n\)。
\(1, 2, 1, 2, ..\)这样放就行。
点击查看代码
void solve() {
int n;
std::cin >> n;
for (int i = 0; i < n; ++ i) {
std::cout << (i % 2 ? 2 : 1) << " \n"[i == n - 1];
}
}
C. 泉神,启动!!!
题意:给你一个\(x\),找一个大于\(1\)的\(y\),使得\(x\times y\)各自数位上的数构成的集合是\(x\)各自数位上的数的集合的子集。
我们可以把两个\(x\)接到一起,那么假设\(x\)的最高位是\(10^i\)次幂,那么我们就要找\(10^{i+1} \times x + x\),发现这个数除上\(x\)就是\(10^{i+1} + 1\)。
点击查看代码
void solve() {
int n;
std::cin >> n;
i64 x = 1;
while (x <= n) {
x *= 10;
}
x = x + 1;
std::cout << x << "\n";
}
D. 大预言家!!!!
题意:按照题目给出的移动方式移动,求第\(t\)秒的坐标。
找规律题,发现走一段时间后路径就会转成一个正方形,大小分别是\(1 \times 1, 3 \times 3, 5 \times 5, ...\),也就是各个奇数的平方。那么二分找到\(t\)秒时在哪个正方形的外层。然后按运动方式走四条边模拟。
点击查看代码
void solve() {
i64 t;
std::cin >> t;
i64 l = 1, r = 1e9;
while (l < r) {
i64 mid = l + r + 1 >> 1ll;
if (mid * mid <= t) {
l = mid;
} else {
r = mid - 1;
}
}
i64 k = l;
if (k % 2 == 0) {
-- k;
}
t -= k * k;
i64 x = k / 2, y = k / 2;
if (t == 0) {
std::cout << x << " " << y << "\n";
return;
}
k += 2;
x += 1;
t -= 1;
i64 a = std::min(t, k - 2);
y -= a;
t -= a;
a = std::min(t, k - 1);
x -= a;
t -= a;
a = std::min(t, k - 1);
y += a;
t -= a;
a = std::min(t, k - 1);
x += a;
std::cout << x << " " << y << "\n";
}
E. 全都要!!!!!
题意:给你一个长度为\(n\)的数组\(a\),第\(i\)个位置上有\(a_i\)的价值,你每次可以走\(1\)到\(6\)步,求走\(k\)步后的最大总价值。
\(f[i][j]\)表示走到\(i\)时用了\(k\)步的最大价值。然后枚举上一步走了几步转移就行。
点击查看代码
void solve() {
int n, k;
std::cin >> n >> k;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
const i64 inf = 1e18;
std::vector f(n + 1, std::vector<i64>(k + 1, -inf));
f[0][0] = 0;
for (int i = 1; i <= n; ++ i) {
for (int j = 1; j <= k; ++ j) {
for (int x = 1; x <= std::min(6, i); ++ x) {
f[i][j] = std::max(f[i][j], f[i - x][j - 1] + a[i - 1]);
}
}
}
i64 ans = -inf;
for (int i = 1; i <= n; ++ i) {
ans = std::max(ans, f[i][k]);
}
std::cout << ans << "\n";
}
F. 水题!!!!!!
题意:有一个矩阵,水从源头开始流下来,遇到障碍物需要\(h\)秒破环它,水流移动一格需要一秒,如果当前水流是垂直向下的并且遇上了障碍物,那么会同时向左右两边流,左右两边的水流不会摧毁下面的障碍物,并且只有遇到下面没有障碍物的情况才会往下流,这时这股水流又可以摧毁障碍物。求到终点的最小时间。
记\(dist[x][y][t], t \in \{0, 1\}\)为水流在\((x, y)\)时不可以\(/\)可以摧毁障碍物的最小时间。那么就分情况看,如果下面没有障碍物就只能往下,否则看能不能摧毁障碍物,能就花\(h + 1\)秒到下面。然后往两边扩展,注意如果一个\(t=0\)的水流往下流那么到下面一格\(t=1\)。
跑\(dijkstra\)即可。
点击查看代码
void solve() {
int n, m, h;
std::cin >> n >> m >> h;
std::vector<std::string> s(n);
for (int i = 0; i < n; ++ i) {
std::cin >> s[i];
}
int sx, sy, tx, ty;
for (int i = 0; i < n; ++ i) {
for (int j = 0; j < m; ++ j) {
if (s[i][j] == '*') {
sx = i, sy = j;
} else if (s[i][j] == '%') {
tx = i, ty = j;
}
}
}
const i64 inf = 1e18;
std::vector dist(n, std::vector(m, std::array<i64, 2>{inf, inf}));
using A = std::array<i64, 4>;
std::priority_queue<A, std::vector<A>, std::greater<A>> heap;
dist[sx][sy][1] = 0;
heap.push({dist[sx][sy][1], sx, sy, 1});
while (heap.size()) {
auto [d, x, y, t] = heap.top(); heap.pop();
// std::cout << d << " " << x + 1 << " " << y + 1 << " " << t << "\n";
if (d != dist[x][y][t]) {
continue;
}
if (x + 1 < n) {
if (t == 1 && s[x + 1][y] == '#' && dist[x + 1][y][1] > dist[x][y][t] + h + 1) {
dist[x + 1][y][1] = dist[x][y][t] + h + 1;
heap.push({dist[x + 1][y][1], x + 1, y, 1});
} else if ((s[x + 1][y] == '.' || s[x + 1][y] == '%') && dist[x + 1][y][1] > dist[x][y][t] + 1) {
dist[x + 1][y][1] = dist[x][y][t]+ 1;
heap.push({dist[x + 1][y][1], x + 1, y, 1});
}
if (s[x + 1][y] == '#' && y + 1 < m && (s[x][y + 1] == '.' || s[x][y + 1] == '%') && dist[x][y + 1][0] > dist[x][y][t] + 1) {
dist[x][y + 1][0] = dist[x][y][t] + 1;
heap.push({dist[x][y + 1][0], x, y + 1, 0});
}
if (s[x + 1][y] == '#' && y - 1 >= 0 && (s[x][y - 1] == '.' || s[x][y - 1] == '%') && dist[x][y - 1][0] > dist[x][y][t] + 1) {
dist[x][y - 1][0] = dist[x][y][t] + 1;
heap.push({dist[x][y - 1][0], x, y - 1, 0});
}
}
}
i64 ans = std::min(dist[tx][ty][0], dist[tx][ty][1]);
if (ans == inf) {
ans = -1;
}
std::cout << ans << "\n";
}