Google Code Jam Round 2 2022 Record
Info
- Practice Link
- Code Repo Link
- Score: 22
- Rank: 1680
Problems
Spiraling Into Control
题意:
给出一个
从
现在要求从
思路:
猜想了一下,当前这一步是否选择跳跃,取决于跳跃后剩余的最大步数是否大于等于可用步数,是的话,就跳跃。
但是大 case TLE 了。
Small Case Code
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <utility>
#include <vector>
#define endl "\n"
#define fi first
#define se second
#define all(x) begin(x), end(x)
#define rall rbegin(a), rend(a)
#define bitcnt(x) (__builtin_popcountll(x))
#define complete_unique(a) a.erase(unique(begin(a), end(a)), end(a))
#define mst(x, a) memset(x, a, sizeof(x))
#define MP make_pair
using ll = long long;
using ull = unsigned long long;
using db = double;
using ld = long double;
using VLL = std::vector<ll>;
using VI = std::vector<int>;
using PII = std::pair<int, int>;
using PLL = std::pair<ll, ll>;
using namespace __gnu_pbds;
using namespace std;
template <typename T>
using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
template <typename T, typename S>
inline bool chmax(T &a, const S &b) {
return a < b ? a = b, 1 : 0;
}
template <typename T, typename S>
inline bool chmin(T &a, const S &b) {
return a > b ? a = b, 1 : 0;
}
// #ifdef LOCAL
// #include <debug.hpp>
// #else
// #define dbg(...)
// #endif
// head
const int N = 1e4 + 10;
int n, k;
int f[N][N];
int mv[][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
void genG() {
int ix = 1;
int mx = 0;
int x = 1, y = 1;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
f[i][j] = -1;
}
}
const auto ok = [](int x, int y) {
if (x < 1 || x > n || y < 1 || y > n) {
return false;
}
if (f[x][y] != -1) {
return false;
}
return true;
};
f[1][1] = 1;
while (ix < n * n) {
++ix;
int nx = x + mv[mx][0];
int ny = y + mv[mx][1];
if (!ok(nx, ny)) {
mx = (mx + 1) % 4;
}
nx = x + mv[mx][0];
ny = y + mv[mx][1];
x = nx;
y = ny;
f[x][y] = ix;
}
}
void printG() {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cout << f[i][j] << " \n"[j == n];
}
}
}
struct node {
int x, y, v;
bool operator<(const node &other) const {
return v > other.v;
}
};
vector<pair<int, int>> gao() {
auto res = vector<pair<int, int>>();
const auto ok = [](int x, int y) {
if (x < 1 || x > n || y < 1 || y > n) {
return false;
}
return true;
};
node cur = {
.x = 1,
.y = 1,
.v = 1,
};
int _k = k;
int target = n * n;
while (_k > 0) {
vector<node> t;
// cout << cur.x << " " << cur.y << " " << cur.v << " " << _k << " " << res.size() << endl;
for (int i = 0; i < 4; i++) {
int nx = cur.x + mv[i][0];
int ny = cur.y + mv[i][1];
if (ok(nx, ny) && f[nx][ny] > cur.v) {
t.emplace_back(node{
.x = nx,
.y = ny,
.v = f[nx][ny],
});
}
}
sort(t.begin(), t.end());
int ok = 0;
for (const auto &nx : t) {
if (_k - 1 <= target - nx.v) {
if (nx.v - cur.v > 1) {
res.push_back(make_pair(cur.v, nx.v));
}
cur = nx;
ok = 1;
break;
}
}
if (ok == 0) {
return vector<pair<int, int>>();
}
--_k;
}
if (cur.v != target) {
return vector<pair<int, int>>();
}
return res;
}
void run() {
cin >> n >> k;
genG();
// printG();
auto res = gao();
if (res.empty()) {
cout << "IMPOSSIBLE\n";
} else {
cout << res.size() << "\n";
for (const auto &it : res) {
cout << it.first << " " << it.second << "\n";
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
cout << fixed << setprecision(20);
int _T = 0;
cin >> _T;
for (int i = 1; i <= _T; ++i) {
cout << "Case #" << i << ": ";
run();
}
return 0;
}
Pixelated Circle
题意:
给出两种在矩阵上「画圆」的函数,求两种方式画出来的「黑点」的数量差异。
思路:
小 case 就将题面中的伪代码翻译一下,然后跑一遍,求个数量的 diff。
Small Case Code
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define endl "\n"
#define fi first
#define se second
#define all(x) begin(x), end(x)
#define rall rbegin(a), rend(a)
#define bitcnt(x) (__builtin_popcountll(x))
#define complete_unique(a) a.erase(unique(begin(a), end(a)), end(a))
#define mst(x, a) memset(x, a, sizeof(x))
#define MP make_pair
using ll = long long;
using ull = unsigned long long;
using db = double;
using ld = long double;
using VLL = std::vector<ll>;
using VI = std::vector<int>;
using PII = std::pair<int, int>;
using PLL = std::pair<ll, ll>;
using namespace __gnu_pbds;
using namespace std;
template <typename T>
using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
template <typename T, typename S>
inline bool chmax(T &a, const S &b) {
return a < b ? a = b, 1 : 0;
}
template <typename T, typename S>
inline bool chmin(T &a, const S &b) {
return a > b ? a = b, 1 : 0;
}
// head
const int N = 1e4 + 10;
int r;
int f[N][N];
int get_pixel(int x, int y) {
return f[x + 100][y + 100];
}
void set_pixel(int x, int y, int v = 0) {
f[x + 100][y + 100] = v;
}
void set_pixel_to_black(int x, int y) {
set_pixel(x, y, 1);
}
int get_all_pixel() {
int res = 0;
for (int i = -r; i <= r; i++) {
for (int j = -r; j <= r; j++) {
res += get_pixel(i, j);
}
}
return res;
}
void init() {
for (int i = -r; i <= r; i++) {
for (int j = -r; j <= r; j++) {
set_pixel(i, j, 0);
}
}
}
void draw_circle_perimeter(int r) {
for (int x = -r; x <= r; x++) {
int y = static_cast<int>(round(sqrt(r * r - x * x)));
set_pixel_to_black(x, y);
set_pixel_to_black(x, -y);
set_pixel_to_black(y, x);
set_pixel_to_black(-y, x);
}
}
void draw_circle_filled_wrong(int r) {
for (int i = 0; i <= r; i++) {
draw_circle_perimeter(i);
}
}
void draw_circle_filled(int r) {
for (int i = -r; i <= r; i++) {
for (int j = -r; j <= r; j++) {
int x = static_cast<int>(round(sqrt(i * i + j * j)));
if (x <= r) {
set_pixel_to_black(i, j);
}
}
}
}
void run() {
cin >> r;
init();
draw_circle_filled(r);
int a = get_all_pixel();
init();
draw_circle_filled_wrong(r);
int b = get_all_pixel();
cout << abs(a - b) << endl;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
cout << fixed << setprecision(20);
int _T = 0;
cin >> _T;
for (int i = 1; i <= _T; ++i) {
cout << "Case #" << i << ": ";
run();
}
return 0;
}
Saving the Jelly
题意:
在一个足球场上,有
第
第
现在有个教练,每次可以指定第
问,有没有方案,使得标号为
思路:
针对小 case:
全排列枚举人拿的顺序,然后暴力 check。
check 的时候,如果某个人在轮到时有多个候选糖果,怎么办?
只要不取
因为如果存在这个人一定得取某一颗糖果,那么最后方案才能跑通的话,那么肯定有另一种排列使得优先级更高的人在前面取走他所需的糖果。
Small Case Code
#include <bits/stdc++.h>
#include <algorithm>
#include <cstring>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <limits>
#include <utility>
#define endl "\n"
#define fi first
#define se second
#define all(x) begin(x), end(x)
#define rall rbegin(a), rend(a)
#define bitcnt(x) (__builtin_popcountll(x))
#define complete_unique(a) a.erase(unique(begin(a), end(a)), end(a))
#define mst(x, a) memset(x, a, sizeof(x))
#define MP make_pair
using ll = long long;
using ull = unsigned long long;
using db = double;
using ld = long double;
using VLL = std::vector<ll>;
using VI = std::vector<int>;
using PII = std::pair<int, int>;
using PLL = std::pair<ll, ll>;
using namespace __gnu_pbds;
using namespace std;
template <typename T>
using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
template <typename T, typename S>
inline bool chmax(T &a, const S &b) {
return a < b ? a = b, 1 : 0;
}
template <typename T, typename S>
inline bool chmin(T &a, const S &b) {
return a > b ? a = b, 1 : 0;
}
// head
int n, vis[12];
long long calcDis(int x, int y, int nx, int ny) {
return 1ll * (x - nx) * (x - nx) + 1ll * (y - ny) * (y - ny);
}
ll dis[30][30];
struct node {
int ix;
long long dis;
bool operator<(const node &other) const {
if (dis == other.dis) {
return ix > other.ix;
}
return dis < other.dis;
}
};
vector<node> disVec[15];
void run() {
cin >> n;
vector<pair<int, int>> f, g;
for (int i = 0; i < n; i++) {
int x, y;
cin >> x >> y;
f.push_back(make_pair(x, y));
}
for (int i = 0; i < n + 1; i++) {
int x, y;
cin >> x >> y;
g.push_back(make_pair(x, y));
}
for (int i = 0; i < n; i++) {
disVec[i].clear();
for (int j = 0; j < n + 1; j++) {
dis[i][j] = calcDis(f[i].first, f[i].second, g[j].first, g[j].second);
disVec[i].push_back(node{
.ix = j,
.dis = dis[i][j],
});
}
sort(disVec[i].begin(), disVec[i].end());
while (!disVec[i].empty() && disVec[i].back().ix != 0) {
disVec[i].pop_back();
}
disVec[i].pop_back();
if (disVec[i].empty()) {
cout << "IMPOSSIBLE\n";
return;
}
}
vector<int> h;
h.reserve(n);
for (int i = 0; i < n; i++) {
h.push_back(i);
}
vector<pair<int, int>> res;
res.reserve(n);
do {
res.clear();
memset(vis, 0, sizeof(vis[0]) * (n + 1));
int all_ok = 1;
for (int i = 0; i < n; i++) {
int ok = 0;
for (const auto &d : disVec[h[i]]) {
if (vis[d.ix]) {
continue;
}
res.emplace_back(make_pair(h[i] + 1, d.ix + 1));
vis[d.ix] = 1;
ok = 1;
break;
}
if (ok == 0) {
all_ok = 0;
break;
}
}
if (all_ok) {
cout << "POSSIBLE\n";
for (const auto &r : res) {
cout << r.first << " " << r.second << "\n";
}
return;
}
} while (next_permutation(h.begin(), h.end()));
cout << "IMPOSSIBLE\n";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
cout << fixed << setprecision(20);
int _T = 0;
cin >> _T;
for (int i = 1; i <= _T; ++i) {
cout << "Case #" << i << ": ";
run();
}
return 0;
}
I, O Bot
题意:
在一个一维平面上,有
ball 有两种形状,0
形状和 1
形状。
收集车上有两个容器,其中一个容器能装 0
形状的 ball,另一个容器能装 1
形状的 ball。
但是可以花费
收集了 ball 之后,收集车可以回到
问将所有球都收集到
思路:
考虑,正负坐标轴是两个独立的子问题,分开做。
在比赛时想了个错误做法。
表示还剩一个 0
形状的 ball 还没收集。表示还剩一个 1
形状的 ball 还没收集。表示前 个 ball 收集完了。
然后 dp 即可。
但是这样会发现样例中的 case2 都过不了。因为它是留了两个 0
形状的 ball,和后面两个 1
形状的 ball,分别组合一起,进行两趟回收。
问题可能出在只维护剩一个 0
/1
形状的 ball 的状态可能不够。但是如果维护的数量大了,空间复杂度又顶不住。
Wrong Code
#include <bits/stdc++.h>
#include <algorithm>
#include <cstring>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <limits>
#include <utility>
#include <vector>
#define endl "\n"
#define fi first
#define se second
#define all(x) begin(x), end(x)
#define rall rbegin(a), rend(a)
#define bitcnt(x) (__builtin_popcountll(x))
#define complete_unique(a) a.erase(unique(begin(a), end(a)), end(a))
#define mst(x, a) memset(x, a, sizeof(x))
#define MP make_pair
using ll = long long;
using ull = unsigned long long;
using db = double;
using ld = long double;
using VLL = std::vector<ll>;
using VI = std::vector<int>;
using PII = std::pair<int, int>;
using PLL = std::pair<ll, ll>;
using namespace __gnu_pbds;
using namespace std;
template <typename T>
using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
template <typename T, typename S>
inline bool chmax(T &a, const S &b) {
return a < b ? a = b, 1 : 0;
}
template <typename T, typename S>
inline bool chmin(T &a, const S &b) {
return a > b ? a = b, 1 : 0;
}
// head
const int N = 1e5 + 10;
int n, C;
struct node {
int x;
int v;
bool operator<(const node &other) const {
return x < other.x;
}
};
ll gao(vector<node> &v) {
int m = v.size();
v.emplace_back(node{
.x = -1,
.v = 0,
});
sort(v.begin(), v.end());
vector<vector<ll>> f(m + 1, vector<ll>(3, 1ll * 10000 * 1e9));
f[0][2] = 0;
for (int i = 1; i <= m; i++) {
ll baseCost = 1ll * v[i].x * 2;
for (int j = 0; j <= 2; j++) {
f[i][j] = min(f[i][j], f[i - 1][j] + baseCost);
}
f[i][v[i].v] = min(f[i][v[i].v], f[i - 1][2]);
f[i][2] = min(f[i][2], f[i - 1][v[i].v ^ 1] + baseCost);
f[i][2] = min(f[i][2], f[i - 1][v[i].v] + baseCost + C);
}
return f[m][2];
}
void run() {
cin >> n >> C;
vector<node> f, g;
for (int i = 0; i < n; i++) {
int x, v;
cin >> x >> v;
if (x < 0) {
f.push_back(node{
.x = -x,
.v = v,
});
} else {
g.push_back(node{
.x = x,
.v = v,
});
}
}
ll ans = 0;
ans += gao(f);
ans += gao(g);
cout << ans << "\n";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
cout << fixed << setprecision(20);
int _T = 0;
cin >> _T;
for (int i = 1; i <= _T; ++i) {
cout << "Case #" << i << ": ";
run();
}
return 0;
}
留坑。
Created: May 15, 2022