2021牛客暑期多校训练营2 个人补题记录
比赛链接:Here
本场 3道签到题可还行,2333
A - Arithmetic Progression
B - Cannon
C - Draw Grids (签到)
题意很简单就不翻译了
手写下 \(n = 1\) 的各个情况,然后拓展到 \(n = 2,3,4\) 就清晰了解法,
只要 \(n,m\) 存在一个偶数,先手必胜
简单来说当一个图上有n个点和n条边的时候,一定成环,感觉这题数据可以再大一点。
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
int n, m;
cin >> n >> m;
cout << (n % 2 == 0 || m % 2 == 0 ? "YES" : "NO");
}
D - Er Ba Game (签到)
细节题,注意区分各种情况
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
int _; for (cin >> _; _--;) {
int a1, b1, a2, b2;
cin >> a1 >> b1 >> a2 >> b2;
if (a1 > b1)swap(a1, b1);
if (a2 > b2)swap(a2, b2);
if (a1 == a2 && b1 == b2) {cout << "tie" << endl; continue;}
if (a1 == 2 && b1 == 8 && !(a2 == 2 && b2 == 8)) {cout << "first" << endl; continue;}
if (!(a1 == 2 && b1 == 8) && a2 == 2 && b2 == 8) {cout << "second" << endl; continue;}
if (a1 == b1 && a2 == b2) {cout << "tie" << endl; continue;}
if (a1 == b1 && a2 != b2) {cout << "first" << endl; continue;}
if (a1 != b1 && a2 == b2) {cout << "second" << endl; continue;}
int t1 = (a1 + b1) % 10, t2 = (a2 + b2) % 10;
if (t1 > t2) {cout << "first" << endl; continue;}
if (t1 < t2) {cout << "second" << endl; continue;}
if (b1 > b2) {cout << "first" << endl; continue;}
if (b1 < b2) {cout << "second" << endl; continue;}
cout << "tie" << endl;
}
}
F - Girlfriend (数学)
淦,又是一道数学题。补题的时候发现比杭电第一场的简单点
题意就不写了
符合条件的显然是两个球的相交。设两点分别为 \((x_1,y_1,z_1),(x_2,y_2,z_2)\) ,那么根据题意,\((x,y,z)\) 需要满足:
那么球心坐标为:\((\frac{k^2x_2-x_1}{k^2-1},\frac{k^2y_2-y_1}{k^2-1},\frac{k^2z_2-z_1}{k^2-1})\)
半径为:\(\sqrt{\frac{x_1^2+y_1^2+z_1^2 - k^2x_2^2 - k^2y_2^2-k^2z_2^2}{k^2-1}+(\frac{x_1-k^2x_2}{k_2-1})^2+(\frac{y_1-k^2y_2}{k_2-1})^2+(\frac{z_1-k^2z_2}{k_2-1})^2}\)
【AC Code】码 Latex 好累呀...
const double pi = acos(-1);
double x[5], y[5], z[5];
double k1, k2;
void solve(double x1, double y1, double z1, double r1, double x2, double y2, double z2, double r2) {
double ans = 0;
double dis = sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) + (z1 - z2) * (z1 - z2));
if (dis >= r1 + r2) ans = 0;
else if (dis + r1 <= r2) ans = (4.00 / 3.00) * pi * r1 * r1 * r1;
else if (dis + r2 <= r1) ans = (4.00 / 3.00) * pi * r2 * r2 * r2;
else {
double cal = (r1 * r1 + dis * dis - r2 * r2) / (2.00 * dis * r1);
double h = r1 * (1 - cal);
ans += (1.00 / 3.00) * pi * (3.00 * r1 - h) * h * h;
cal = (r2 * r2 + dis * dis - r1 * r1) / (2.00 * dis * r2);
h = r2 * (1.00 - cal);
ans += (1.00 / 3.00) * pi * (3.00 * r2 - h) * h * h;
}
printf("%.3f\n", ans);
}
int read() {
int x = 0, f = 1; char c = getchar();
while (c < '0' || c > '9') { if (c == '-') f = -1; c = getchar(); }
while (c >= '0' && c <= '9') { x = (x << 1) + (x << 3) + (c ^ 48); c = getchar();}
return x * f;
}
int main() {
int T = read();
while (T--) {
for (int i = 0; i < 4; i++) x[i] = read(), y[i] = read(), z[i] = read();
k1 = read(), k2 = read();
double c1x, c1y, c1z, c1r, t;
c1x = (k1 * k1 * x[1] - x[0]) / (k1 * k1 - 1);
c1y = (k1 * k1 * y[1] - y[0]) / (k1 * k1 - 1);
c1z = (k1 * k1 * z[1] - z[0]) / (k1 * k1 - 1);
t = k1 * k1 * ((x[1] * x[1]) + (y[1] * y[1]) + (z[1] * z[1])) - x[0] * x[0] - y[0] * y[0] - z[0] * z[0];
t /= (k1 * k1 - 1);
c1r = sqrt(c1x * c1x + c1y * c1y + c1z * c1z - t);
double c2x, c2y, c2z, c2r;
c2x = (k2 * k2 * x[3] - x[2]) / (k2 * k2 - 1);
c2y = (k2 * k2 * y[3] - y[2]) / (k2 * k2 - 1);
c2z = (k2 * k2 * z[3] - z[2]) / (k2 * k2 - 1);
t = k2 * k2 * ((x[3] * x[3]) + (y[3] * y[3]) + (z[3] * z[3])) - x[2] * x[2] - y[2] * y[2] - z[2] * z[2];
t /= (k2 * k2 - 1);
c2r = sqrt(c2x * c2x + c2y * c2y + c2z * c2z - t);
solve(c1x, c1y, c1z, c1r, c2x, c2y, c2z, c2r);
}
return 0;
}
不过本题似乎有其他数学写法,欢迎补充
G - League of Legends
H - Olefin
I - Penguins (搜索)
题意大意:
两个 \(20 \times 20\) 的地图,两个玩家操作的角色分别需要从 \((20,20),(20,1)\) 走到 \((1,20),(1,1)\),同时需在地图上用 A
记录最短路径并输出
裸的 BFS 保存路径的搜索?
我这里把两个图一起搜了,如果怕写乱也可拆开来跑两次BFS
【AC Code】注意细节
const int N = 30, inf = 0x3f3f3f3f;
char e1[N][N], e2[N][N], path[N * N * 2], dir[] = {'D', 'L', 'R', 'U'};
int cnt;
struct node {
int x1, y1, x2, y2;// 当前坐标
} pre[N][N][N][N];
int d[N][N][N][N], p[N][N][N][N];
int Dir[4][4] = {1, 0, 1, 0, 0, -1, 0, 1, 0, 1, 0, -1, -1, 0, -1, 0};
void BFS() {
queue<node>q;
memset(d, inf, sizeof(d));
d[20][20][20][1] = 0;
q.push(node{20, 20, 20, 1});
while (!q.empty()) {
node tmp = q.front();
q.pop();
int x1 = tmp.x1, y1 = tmp.y1, x2 = tmp.x2, y2 = tmp.y2;
int dis = d[x1][y1][x2][y2];
for (int i = 0; i < 4; ++i) {
int u1 = x1 + Dir[i][0], v1 = y1 + Dir[i][1];
int u2 = x2 + Dir[i][2], v2 = y2 + Dir[i][3];
if (e1[u1][v1] != '.')u1 -= Dir[i][0], v1 -= Dir[i][1];
if (e2[u2][v2] != '.')u2 -= Dir[i][2], v2 -= Dir[i][3];
if (dis + 1 < d[u1][v1][u2][v2]) {
d[u1][v1][u2][v2] = dis + 1;
pre[u1][v1][u2][v2] = node{x1, y1, x2, y2};
p[u1][v1][u2][v2] = i;
q.push(node{u1, v1, u2, v2});
}
}
}
}
void solve(node u) {
int x1 = u.x1, y1 = u.y1, x2 = u.x2, y2 = u.y2;
e1[x1][y1] = e2[x2][y2] = 'A';
if (x1 == 20 and y1 == 20 and x2 == 20 and y2 == 1)return ;
solve(pre[x1][y1][x2][y2]);
path[cnt++] = dir[p[x1][y1][x2][y2]];
}
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
for (int i = 1; i <= 20; ++i)scanf("%s %s", e1[i] + 1, e2[i] + 1);
BFS();
solve(node{1, 20, 1, 1});
cout << cnt << "\n" << path << "\n";
for (int i = 1; i <= 20; ++i)printf("%s %s\n", e1[i] + 1, e2[i] + 1);
}
J - Product of GCDs
K - Stack (签到)
比赛时,学长指出K题是构造一个前 \(p_i\) 个数中非降子序列长度为 \(a_i\) 的数组
但细节上没处理好。
这道题实际上可直接模拟,先填好给出的 \(k\) 个位置,然后补充空位 if (!a[i])a[i] = a[i - 1] + 1;
但填充过程发现 if (a[i] > a[i - 1] + 1)
则可以直接输出 -1
了
剩下就是直接模拟题意了
另外 K神 有一个树状数组的解法,值得学习一下
const int N = 1e6 + 10;
int a[N];
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
int n, k;
cin >> n >> k;
while (k--) {
int x, y; cin >> x >> y;
a[x] = y;
}
for (int i = 1; i <= n; ++i) {
if (!a[i])a[i] = a[i - 1] + 1;
else if (a[i] > a[i - 1] + 1) {
cout << -1;
return 0;
}
}
stack<int>stk;
int t = 1;
for (int i = n; i > 0; --i) {
while (stk.size() < a[i])stk.push(t++);
a[i] = stk.top(); stk.pop();
}
for (int i = 1; i <= n; ++i)
cout << a[i] << " \n"[i == n];
}