1373、两只奶牛
模拟牛、农民的移动
import java.util.*;
import java.io.*;
public class Main {
static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
static BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
static char[][] map = new char[10][10];
static boolean check(int x, int y) {
if (x < 0 || y < 0 || x >= 10 || y >= 10 || map[x][y] == '*') return false;
return true;
}
public static void main(String[] args) throws IOException {
Scanner scanner = new Scanner(System.in);
int x1 = 0, x2 = 0;
int y1 = 0, y2 = 0;
for (int i = 0; i < 10; i++) {
map[i] = scanner.nextLine().toCharArray();
for (int j = 0; j < 10; j++) {
if (map[i][j] == 'F') {
x1 = i;
y1 = j;
}
if (map[i][j] == 'C') {
x2 = i;
y2 = j;
}
}
}
// 分别代表:上右下左
int[][] dirs = new int[][] {{-1,0},{0,1},{1,0},{0,-1}};
// 起始方向
int d1 = 0;
int d2 = 0;
boolean flag = false;
for (int i = 0; i < 10000000; i++) {
if (x1 == x2 && y1 == y2) {
System.out.println(i);
flag = true;
break;
}
int nx1 = x1 + dirs[d1][0];
int ny1 = y1 + dirs[d1][1];
int nx2 = x2 + dirs[d2][0];
int ny2 = y2 + dirs[d2][1];
if (!check(nx1, ny1)) {
d1 = (d1 + 1) % 4;
} else {
x1 = nx1;
y1 = ny1;
}
if (!check(nx2, ny2)) {
d2 = (d2 + 1) % 4;
} else {
x2 = nx2;
y2 = ny2;
}
}
if (flag == false) System.out.println(0);
}
}
唯一要注意的是如何判断永不相遇的情况,Y总的思路是在10×10的矩阵中有100个位置,每个位置有4个状态,所有400个状态,人和牛都有400个状态,所以有400×400 = 1.6e5种状态,所以最多重复这么多次后必然会循环,说明永远无法相遇。
1353、滑雪场设计
可以先将山峰高度排序,只要保证最大山峰高度 - 最小山峰的高度 <= 17即可,也即我们要找到一个最优的最小山峰高度,使得最大山峰高度 - 最小山峰高度 <= 17,并且取得这个最小山峰的代价最小。这个最优最小的山峰高度所在范围应该是:[最小山峰高度,最大山峰高度-17]
例如题目中的最佳最小山峰高度就 = 4,所以只需要去枚举最优最小的山峰高度,对于所有山峰高度,如果小于它,就要增加高度,大于它+17,就要减少高度,取最优最小的山峰高度的最小值即可。(确实是贪心的思想,但是自己没想到)
import java.util.*;
import java.io.*;
public class Main {
static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
static BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
public static void main(String[] args) throws IOException {
String[] input = reader.readLine().trim().split(" ");
int n = Integer.parseInt(input[0]);
int[] hei = new int[n];
for (int i = 0; i < n; i++) {
hei[i] = Integer.parseInt(reader.readLine().trim());
}
Arrays.sort(hei);
// 遍历范围[最小山峰高度, 最大山峰高度-17]
int ans = Integer.MAX_VALUE;
for (int i = hei[0]; i <= hei[n - 1] - 17; i++) {
int tmp = 0;
for (int cur : hei) {
if (cur < i) tmp += (cur - i) * (cur - i);
else if (cur > i + 17) tmp += (cur - i - 17) * (cur - i - 17);
}
ans = Math.min(tmp, ans);
}
System.out.println(ans);
}
}
1354、等差数列(中等)
简单模拟,数据量小,先找到双平方数集合,然后枚举可能的等差数列前两项即可。
import java.util.*;
import java.io.*;
class node {
// 分别记录首项和公差
int a, b;
node (int a, int b) {
this.a = a;
this.b = b;
}
}
public class Main {
static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
static BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
public static void main(String[] args) throws IOException {
String[] input = reader.readLine().trim().split(" ");
int n = Integer.parseInt(input[0]);
input = reader.readLine().trim().split(" ");
int m = Integer.parseInt(input[0]);
int top = m * m + m * m;
boolean[] vis = new boolean[top + 1];
// 枚举双平方数集合
for (int i = 0; i <= m; i++) {
for (int j = 0; j <= m; j++) {
vis[i * i + j * j] = true;
}
}
List<node> list = new ArrayList<>();
// 枚举等差数列的前两项
for (int i = 0; i <= top; i++) {
if (!vis[i]) continue;
for (int j = i + 1; j <= top; j++) {
if (!vis[j]) continue;
// 找到数列的公差d,以及在长度n下的最后一项
int d = j - i;
int last = i + d * (n - 1);
if (last > top) break;
boolean flag = true;
for (int k = j + d; k <= last; k += d) {
if (!vis[k]) {
flag = false;
break;
}
}
// 是满足的
if (flag) {
list.add(new node(i, d));
}
}
}
if (list.isEmpty()) {
writer.write("NONE");
} else {
Collections.sort(list, new Comparator<node>() {
@Override
public int compare(node o1, node o2) {
if (o1.b != o2.b) return o1.b - o2.b;
else return o1.a - o2.a;
}
});
for (node cur : list) {
writer.write(cur.a + " " + cur.b + "\n");
}
}
writer.flush();
}
}
1761、阻挡广告牌(简单)
把广告牌的所在矩阵位置标记为1,卡车在的位置和没有广告牌的位置都标记为0,统计1的个数即可。
import java.util.*;
import java.io.*;
public class Main {
static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
static BufferedWriter log = new BufferedWriter(new OutputStreamWriter(System.out));
public static void main(String[] args) throws IOException {
String[] input = reader.readLine().trim().split(" ");
int x1 = Integer.parseInt(input[0]) + 1000;
int y1 = Integer.parseInt(input[1]) + 1000;
int x2 = Integer.parseInt(input[2]) + 1000;
int y2 = Integer.parseInt(input[3]) + 1000;
input = reader.readLine().trim().split(" ");
int x3 = Integer.parseInt(input[0]) + 1000;
int y3 = Integer.parseInt(input[1]) + 1000;
int x4 = Integer.parseInt(input[2]) + 1000;
int y4 = Integer.parseInt(input[3]) + 1000;
input = reader.readLine().trim().split(" ");
int cx1 = Integer.parseInt(input[0]) + 1000;
int cy1 = Integer.parseInt(input[1]) + 1000;
int cx2 = Integer.parseInt(input[2]) + 1000;
int cy2 = Integer.parseInt(input[3]) + 1000;
int[][] g = new int[2010][2010];
for (int i = 0; i <= 2000; i++) {
for (int j = 0; j <= 2000; j++) {
if (i > x1 && i <= x2 && j > y1 && j <= y2) {
g[i][j] = 1;
}
if (i > x3 && i <= x4 && j > y3 && j <= y4) {
g[i][j] = 1;
}
if (i > cx1 && i <= cx2 && j > cy1 && j <= cy2) {
g[i][j] = 0;
}
}
}
int ans = 0;
for (int i = 0; i <= 2000; i++) {
for (int j = 0; j <= 2000; j++) {
if (g[i][j] == 1) ans++;
}
}
System.out.println(ans);
}
}
青云杯:完全平方数
这道题是蓝桥杯2021年原题,很简单,把当前给出的n进行质因数分解,例如12 = 2 x 2 x 3,把奇数个的质因数,补成偶数个,12就还需要补个3,就可以达到完全平方数,也就是说完全平方数的质因子数一定是偶数个。
当是指数时,例如:17,只能分出17,所以再乘上自己即可。
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
long n = scan.nextLong();
long res = 1;
// 只需要考虑到根号n即可
for (long i = 2; i * i <= n; i++) {
if (n % i == 0) {
int cnt = 0;
while (n % i == 0) {
// n也是跟着除的
n /= i;
cnt++;
}
// 累乘指数为奇数的质因子
if (cnt % 2 == 1) {
res *= i;
}
}
}
// n为质数时,res=1,满足
System.out.println(res * n);
}
}
青云杯:列车调度
模拟火车进轨道的过程, 第一辆火车肯定直接进入,新开一个轨道,后序火车应该放在数字比自身大的火车的轨道后面(也就是替换掉当前轨道的之前的火车),也就是二分中的:找到第一个比自身大的数!,如果没找到就会返回数组长度。
比赛场上,根本没想到…,只知道应该把递减的数字放在一起,看可以拆分出多少个递减数组序列,看了看数据规模觉得是二分、排序、双指针,但是没想到真是二分…
import java.util.*;
import java.io.*;
public class Main {
static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
static BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
static int[] dp = new int[100005];
static int cnt = 0;
static int binarySearch(int v) {
int left = 0, right = cnt;
// 找第一个大于key的下标
while (left < right) {
int mid = (left + right) >> 1;
if (dp[mid] > v) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
public static void main(String[] args) throws IOException, Exception {
String[] input = reader.readLine().trim().split(" ");
int n = Integer.parseInt(input[0]);
int[] num = new int[n];
input = reader.readLine().trim().split(" ");
for (int i = 0; i < n; i++) {
int cur = Integer.parseInt(input[i]);
if (i == 0) dp[cnt++] = cur; // 第一辆车进来
else {
// 二分找这辆车应该放在的轨道,应该放在比前面数更小的轨道上
// 当前列车小于最后一个进去的列车时,就二分查找到第一个大于它的位置并将其值改为当前列车
int next = binarySearch(cur);
if (next == cnt) dp[cnt++] = cur; // 说明没找到大于当前数的下标位置,说明要新开铁轨
else dp[next] = cur;
}
}
System.out.println(cnt);
}
}
青云杯:完全二叉树的层序遍历
因为题目给出的是完全二叉树,所以才使得通过后序遍历得到层序遍历成为了可能。一定要区分:完美二叉树和完全二叉树,完美二叉树也称满二叉树,由其名字可以知道,它的节点都是塞满了的。而完全二叉树,可能是满二叉树,也有可能不是,它可以最后一层节点不放满,但必须从左到右放。
import java.util.*;
import java.io.*;
public class Main {
static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
static BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out));
static int n;
static int[] tree = new int[32];
static Scanner scan = new Scanner(System.in);
public static void main(String[] args) throws IOException, Exception {
n = scan.nextInt();
create(1); // 根节点为1
// 通过后序遍历构建出来的树,直接输出该数组就是层序遍历结果
for (int i = 1; i <= n; i++) {
if (i > 1) System.out.print(" ");
System.out.print(tree[i]);
}
}
static void create(int i) throws Exception, IOException {
if (i > n) return;
// 利用完全二叉树的特性,左子树节点:2 * i,右子树节点:2 * i + 1
create(2 * i); // 根节点的左孩子节点
create(2 * i + 1); // 根节点的有孩子节点
// 后序遍历的特点,先构建左、右孩子,再构建根节点
tree[i] = scan.nextInt();
}
}