牛客小白月赛21–题解报告
时间:2020.01.19
个人博客:https://wyjoutstanding.github.io/
第一次参加算法比赛,记录一下
文章目录
题号 | 考点 | 备注 |
---|---|---|
A | 外心坐标计算 | 手算/线性方程 |
B | 哈诺塔递归设计 | 手动调试 |
C | 前缀和/线性化 | 固定起点(日期计算) |
D | 拓扑排序,通路计数 | 简单dp,bfs |
E | 简单模拟 | 注意四舍五入 |
F | 找规律,大整数 | 手动猜想/通式带入化简 |
G | 质因数分解 | 仅需计算质因数个数 |
H | 直接输出 | 签到题 |
I | 子序列计数dp | 包括连续和非连续,滚动数组优化(逆序遍历) |
J | 三维迷宫 | BFS搜索6个方向 |
难度排序:
- 签到:H
- 常规:A,C,E,J(简单模拟)
- 思考:F,G(规律找到后巨简单)
- 较难:B,D,I(设计dp,图论,递归搜索)
A. Audio
思路分析
已知三点坐标,求解外心坐标(中垂线交点)。
-
可直接用两点式写出直线方程,联立求解二元一次方程,手算出(x,y)结果。
-
或者用高斯消元求解线性方程。
AC代码(C++11,手算xy)
#include<bits/stdc++.h>
using namespace std;
int main() {
double p[3][2], m[2][2], A[2], B[2]; // 三点坐标,中点坐标,中垂线法向量
for (int i = 0; i < 3; i ++) scanf("%lf %lf", &p[i][0], &p[i][1]);
for (int i = 0; i < 2; i ++) {
m[i][0] = (p[i][0] + p[i+1][0]) / 2; // x
m[i][1] = (p[i][1] + p[i+1][1]) / 2; // y
A[i] = p[i][0] - p[i+1][0]; // 法向量x
B[i] = p[i][1] - p[i+1][1]; // 法向量y
}
double x, y;
x = -(-B[1]*A[0]*m[0][0] - B[0]*B[1]*m[0][1] + B[0]*B[1]*m[1][1] + B[0]*A[1]*m[1][0]) / (B[1]*A[0] - B[0]*A[1]);
y = m[0][1] - A[0]*(x-m[0][0])/B[0];
printf("%.3lf %.3lf\n", x, y);
return 0;
}
B. Bits
思路分析
极有意思的一道题,深入理解了汉诺塔递归抽象原理。
只需在原来的汉诺塔基础上,控制奇偶放置位置即可。
递归设计比较简单,建议手动演示推导。
void hanoi(int n, vector<int>& A, vector<int>& B, vector<int>& C) {
// 递归实现:表示将A柱上n个盘子借助B移动到C
if (n == 1) {
// 1个直接移动
move(A, C);
return;
}
hanoi(n-1, A, C, B); // A柱上n-1个盘子借助C移动到B
move(A, C);
hanoi(n-1, B, A, C);
}
AC代码(C++11,汉诺塔递归设计)
#include<bits/stdc++.h>
using namespace std;
int n, cnt = 0, p[3]; // 总个数,移动次数,三根柱子的位置
vector<int> V[3]; // 3个柱子