蓝桥杯总结与练习(一)模拟与高精度(包括日期相关算法)

(一)模拟与高精度

想必大家都听说过“数学建模”这个东西,模拟其实也不难,相当于“计算机建模”,就是用计算机代码去模拟一些事件或规律,而这些规律题目已经直接过着间接得告诉你了,我们通常通过for循环和if判断就可以把事件或规律模拟出来了。
根据规律,我大致分类以下三类问题:(1)简单模拟问题 。(2)高精度计算问题。(3)日期模拟问题


(1)简单模拟问题

这类问题呢,也很简单,题目怎么 “说”,我们就怎么做,注意 “说”,可能题目不会直接告诉你规律,你可能需要观察输出来找到题目所 “说” 的规律。
这一类题目没有固定的模板,所以先通过两个例子来看一下通常是怎么解决这些问题的。

龟兔赛跑预测(左键传送门)

题目描述

话说这个世界上有各种各样的兔子和乌龟,但是 研究发现,所有的兔子和乌龟都有一个共同的特点——喜欢赛跑。于是世界上各个角落都不断在发生着乌龟和兔子的比赛,小华对此很感兴趣,于是决定研究不同兔 子和乌龟的赛跑。他发现,兔子虽然跑比乌龟快,但它们有众所周知的毛病——骄傲且懒惰,于是在与乌龟的比赛中,一旦任一秒结束后兔子发现自己领先t米或以 上,它们就会停下来休息s秒。对于不同的兔子,t,s的数值是不同的,但是所有的乌龟却是一致——它们不到终点决不停止。
然而有些比赛相当漫长,全程观看会耗费大量时间,而小华发现只要在每场比赛开始后记录下兔子和乌龟的数据——兔子的速度v1(表示每秒兔子能跑v1 米),乌龟的速度v2,以及兔子对应的t,s值,以及赛道的长度l——就能预测出比赛的结果。但是小华很懒,不想通过手工计算推测出比赛的结果,于是他找 到了你——清华大学计算机系的高才生——请求帮助,请你写一个程序,对于输入的一场比赛的数据v1,v2,t,s,l,预测该场比赛的结果。

输入

输入只有一行,包含用空格隔开的五个正整数v1,v2,t,s,l,其中(v1,v2< =100;t< =300;s< =10;l< =10000且为v1,v2的公倍数)
输出
输出包含两行,第一行输出比赛结果——一个大写字母“T”或“R”或“D”,分别表示乌龟获胜,兔子获胜,或者两者同时到达终点。
第二行输出一个正整数,表示获胜者(或者双方同时)到达终点所耗费的时间(秒数)。

样例输入

10 5 5 2 20

样例输出

D
4

题目分析:

通过时间流动来模拟事件的进行,有几个注意点:
1.时间要一秒一秒的流动,如果通过跳动来模拟兔子睡觉的过程,会出现错误。
2.兔子进入睡眠状态的判断,和醒来的判断。

AC代码:

package Algorithm;

import java.util.Scanner;

/**
 * Created by IntelliJ IDEA.
 * User: ShiYu Huang
 * Date: 2021/1/31
 */
public class Day07TortoiseAndTheHare {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        //读取参数数据
        int v1 = sc.nextInt();
        int v2 = sc.nextInt();
        int t = sc.nextInt();
        int sleep = sc.nextInt();
        int l = sc.nextInt();
        //设定初始时间time,兔子初始路程s1,乌龟初始路程s2
        //兔子睡了几分钟sleep_flag,兔子是否处于睡觉状态
        int time = 0, s1 = 0, s2 = 0, sleep_flag = 0, sleep_trun = 0;
        
        while (s1 < l && s2 < l) {
            time++;//时间流动
            s2 += v2;//乌龟无论何时都往前进
            if (sleep_trun == 0) {//兔子没有睡觉就继续跑,否则睡一分钟
                s1 += v1;
            } else {
                sleep_flag++;
                if (sleep_flag == sleep) {//兔子醒来
                    sleep_trun = 0;
                }
            }
            if (s1 - s2 >= t && sleep_trun == 0) {//如果兔子是醒的且超过了乌龟,就要睡觉
                sleep_trun = 1;
                sleep_flag = 0;
            }
        }
        if (s1 > s2) {
            System.out.println("R");
        } else if (s1 == s2) {
            System.out.println("D");
        } else {
            System.out.println("T");
        }
        System.out.println(time);
    }
}


扫雷游戏(左键传送门)

题目描述

扫雷游戏是一款十分经典的单机小游戏。在nn行mm列的雷区中有一些格子含有地雷(称之为地雷格),其他格子不含地雷(称之为非地雷格)。玩家翻开一个非地雷格时,该格将会出现一个数字——提示周围格子中有多少个是地雷格。游戏的目标是在不翻出任何地雷格的条件下,找出所有的非地雷格。
现在给出nn行mm列的雷区中的地雷分布,要求计算出每个非地雷格周围的地雷格数。
注:一个格子的周围格子包括其上、下、左、右、左上、右上、左下、右下八个方向上与之直接相邻的格子。

输入格式

第一行是用一个空格隔开的两个整数nn和mm,分别表示雷区的行数和列数。
接下来nn行,每行mm个字符,描述了雷区中的地雷分布情况。字符’*’表示相应格子是地雷格,字符’?’表示相应格子是非地雷格。相邻字符之间无分隔符。

输出格式

输出文件包含nn行,每行mm个字符,描述整个雷区。用’*’表示地雷格,用周围的地雷个数表示非地雷格。相邻字符之间无分隔符。

输入输出样例

输入 #1

3 3
*??
???
?*?

输出 #1

*10
221
1*1

输入 #2

2 3
?*?
*??

输出 #2

2*1
*21

说明/提示

对于 100%100%的数据, 1≤n≤100, 1≤m≤1001≤n≤100,1≤m≤100。

题目分析:

用二位数组将读取的矩阵存储起来,一个一个遍历,读到 * 跳过,读到 ? 就开始统计,统计当前位置的个方位藏雷的数量,注意:需要判断是否越界。

AC代码:

package 洛谷.模拟与高精度;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class P2670 {
	public static void main(String[] args) throws IOException {
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		String[] input = in.readLine().split(" ");
		int n = Integer.parseInt(input[0]), m = Integer.parseInt(input[1]);
		char[][] map = new char[n][m];
   		//读入给出的矩阵
		for (int i = 0; i < n; i++) {
			String s = in.readLine();
			for (int j = 0; j < m; j++) {
				map[i][j] = s.charAt(j);
			}
		}
		
		//遍历并进行统计
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
			    //统计到*跳过
				if (map[i][j] == '*') {
					continue;
				}
				int cnt = 0;//统计的数目
				
				//以下第一个条件判断是否越界,第二个条件判断有否是雷
				if (i - 1 >= 0) {//北
					if (map[i - 1][j] == '*') {
						cnt++;
					}
				}
				if (i - 1 >= 0 && j + 1 < m) {//东北
					if (map[i - 1][j + 1] == '*') {
						cnt++;
					}
				}
				if (j + 1 < m) {//东
					if (map[i][j + 1] == '*') {
						cnt++;
					}
				}
				if (i + 1 < n && j + 1 < m) {//东南
					if (map[i + 1][j + 1] == '*') {
						cnt++;
					}
				}
				if (i + 1 < n) {//南
					if (map[i + 1][j] == '*') {
						cnt++;
					}
				}
				if (i + 1 < n && j - 1 >= 0) {//西南
					if (map[i + 1][j - 1] == '*') {
						cnt++;
					}
				}
				if (j - 1 >= 0) {//西
					if (map[i][j - 1] == '*') {
						cnt++;
					}
				}
				if (i - 1 >= 0 && j - 1 >= 0) {//西北
					if (map[i - 1][j - 1] == '*') {
						cnt++;
					}
				}
				map[i][j] = (char) (cnt + '0');//修改当前位置为统计到的周围雷数
			}
		}

		//遍历输出
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				System.out.print(map[i][j]);
			}
			System.out.println();
		}
	}
}

玩具谜题

题目描述

小南有一套可爱的玩具小人, 它们各有不同的职业。
有一天, 这些玩具小人把小南的眼镜藏了起来。 小南发现玩具小人们围成了一个在这里插入图片描述
圈,它们有的面朝圈内,有的面朝圈外。如下图:
这时singer告诉小南一个谜題: “眼镜藏在我左数第3个玩具小人的右数第1个玩具小人的左数第2个玩具小人那里。 ”
小南发现, 这个谜题中玩具小人的朝向非常关键, 因为朝内和朝外的玩具小人的左右方向是相反的: 面朝圈内的玩具小人, 它的左边是顺时针方向, 右边是逆时针方向; 而面向圈外的玩具小人, 它的左边是逆时针方向, 右边是顺时针方向。
小南一边艰难地辨认着玩具小人, 一边数着:
singersinger朝内, 左数第3个是archer。
archerarcher朝外,右数第1个是thinker。
thinkerthinker朝外, 左数第2个是write。
所以眼镜藏在writerwriter这里!
虽然成功找回了眼镜, 但小南并没有放心。 如果下次有更多的玩具小人藏他的眼镜, 或是谜題的长度更长, 他可能就无法找到眼镜了 。 所以小南希望你写程序帮他解决类似的谜題。 这样的谜題具体可以描述为:
有 n个玩具小人围成一圈, 已知它们的职业和朝向。现在第11个玩具小人告诉小南一个包含m条指令的谜題, 其中第 z条指令形如“左数/右数第s,个玩具小人”。 你需要输出依次数完这些指令后,到达的玩具小人的职业。

输入格式

输入的第一行包含两个正整数 n,m,表示玩具小人的个数和指令的条数。
接下来 n 行,每行包含一个整数和一个字符串,以逆时针为顺序给出每个玩具小人的朝向和职业。其中 0 表示朝向圈内,11表示朝向圈外。 保证不会出现其他的数。字符串长度不超过 10 且仅由小写字母构成,字符串不为空,并且字符串两两不同。整数和字符串之间用一个空格隔开。
接下来 m 行,其中第 ii 行包含两个整数 a_i,s_i
,表示第 i 条指令。若 a_i=0,表示向左数 s
i个人;若 a_i=1,表示向右数 s_is
i​个人。 保证 a_i 不会出现其他的数,1 <= s_i <n。

输出格式

输出一个字符串,表示从第一个读入的小人开始,依次数完 m 条指令后到达的小人的职业。

输入输出样例

输入 #1

7 3
0 singer
0 reader
0 mengbier
1 thinker
1 archer
0 writer
1 mogician
0 3
1 1
0 2

输出 #1

writer

输入 #2

10 10
1 C
0 r
0 P
1 d
1 e
1 m
1 t
1 y
1 u
0 V
1 7
1 1
1 4
0 5
0 3
0 1
1 6
1 2
0 8
0 4

输出 #2

y


题目分析:

①创建一个类 Man 存储每个小人的名字和转向,并写出基本方法, (C可以使用结构体)

class Man {
	int flag = 0;
	String name;

	Man(int flag, String name) {
		this.flag = flag;
		this.name = name;
	}

	public int getFlag() {
		return flag;
	}

	public String getName() {
		return name;
	}
}

②使用 ArrayList添加所有Man对象存储起来,默认当前位置是1号位(下标为0)。
③读取指令,读取指令后,方向要和当前位置的人的朝向进行判断,如果朝内,方向就和指令的方向一致,否则相反。然后根据方向改变位置。
④如果位置非法了,即使合法化位置,不然要出现越界的问题。

AC代码:

package 洛谷.模拟与高精度;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

public class P1653 {
	public static void main(String[] args) throws IOException {
		ArrayList<Man> al = new ArrayList<>();
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		String[] input = in.readLine().split(" ");
		int n = Integer.parseInt(input[0]), m = Integer.parseInt(input[1]);
		
		//添加玩具
		for (int i = 0; i < n; i++) {
			input = in.readLine().split(" ");
			al.add(new Man(Integer.parseInt(input[0]), input[1]));
		}
		int x = 0;
		for (int i = 0; i < m; i++) {
			input = in.readLine().split(" ");
			int point = Integer.parseInt(input[0]);
			int step = Integer.parseInt(input[1]);

			if (point == al.get(x).getFlag()) {//根据指令来判断向左还是向右
				x -= step;
			} else {
				x += step;
			}
			
			//如果数据非法,将数据合法化
			if (x < 0) {
				x += n;
			}
			if (x >= n) {
				x %= n;
			}
		}
		System.out.println(al.get(x).getName());
	}
}

class Man {
	int flag = 0;
	String name;

	Man(int flag, String name) {
		this.flag = flag;
		this.name = name;
	}

	public int getFlag() {
		return flag;
	}

	public String getName() {
		return name;
	}
}

(2)高精度计算

学过编程语言我们知道,存放一个整数有int类型和long类型,而long类型最多也就存储-9223372036854775808到9223372036854775807之间的数,而超出的咋弄呢,所以就要用到高精度计算。高精度计算本来是归类到基础数学算法里面的,而我认为其不过就是模拟小学手算的过程,所以也归类模拟里面了。
下面通过几个例子来学习高精度。


高精度加法(左键传送门)

题目描述

高精度加法,相当于a+b problem,不用考虑负数.

输入格式

分两行输入。a,b≤10500
500

输出格式

输出只有一行,代表a+b的值

输入 #1

1
1

输出 #1

2

输入 #2

1001
9099

输出 #2

10100

分析:

让我们来回忆一下小学怎么计算加法的!

如下图(以1989+14537为例子):
在这里插入图片描述
初始进位为0
9+7+0=16,末尾为6,进位为1
8+3+1=12,末尾为2,进位为1
9+5+1=15,末尾为5,进位为1
1+4+1=6,末尾为6,进位为0
1+0+0=0,末尾为0,进位为0

为了更加直观表达意思:我们这样写(低位在前):

在这里插入图片描述

AC代码:

package 洛谷.模拟与高精度;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

public class P1601 {
	public static void main(String[] args) throws IOException {
		ArrayList<Integer> x1 = new ArrayList<>();
		ArrayList<Integer> x2 = new ArrayList<>();
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
		String s1 = in.readLine();
		String s2 = in.readLine();
		//记录两个数字中大的那一个长度,方便补零
		int max = s1.length() >= s2.length() ? s1.length() : s2.length();

		//将字符串按低位到高位存到列表中
		for (int i = s1.length() - 1; i >= 0; i--) {
			x1.add(s1.charAt(i) - '0');
		}
		for (int i = s2.length() - 1; i >= 0; i--) {
			x2.add(s2.charAt(i) - '0');
		}

		//按照长的去补零,防止越界
		for (int i = 0; i < max - s1.length(); i++) {
			x1.add(0);
		}
		for (int i = 0; i < max - s2.length(); i++) {
			x2.add(0);
		}

		//模拟手算的过程
		int up = 0;
		for (int i = 0; i < x1.size(); i++) {
			int temp = x1.get(i) + x2.get(i) + up;
			x1.set(i, temp % 10);
			up = temp / 10;
		}

		//如果算完进位还有剩余,就把进位直接加到最高位去
		if (up != 0) {
			x1.add(up);
		}
		for (int i = x1.size() - 1; i >= 0; i--) {
			System.out.print(x1.get(i));
		}
	}
}


高精度乘法

思路大概类似:
还是举一个例子(1889*14537)来说:
在这里插入图片描述

AC代码:

package 洛谷.模拟与高精度;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

public class P1303 {
	public static void main(String[] args) throws IOException {
		ArrayList<Integer> a1 = new ArrayList<>();//第一个数
		ArrayList<Integer> a2 = new ArrayList<>();//第二个数
		ArrayList<Integer> res = new ArrayList<>();//结果数
		// 预置好-1,-1表示未访问,后面好判断大数字的位数
		for (int i = 0; i < 20010; i++) {
			res.add(-1);
		}
		BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

		//读取和转换数字
		String s1 = in.readLine();
		String s2 = in.readLine();
		for (int i = s1.length() - 1; i >= 0; i--) {
			a1.add((s1.charAt(i) - '0'));
		}
		for (int i = s2.length() - 1; i >= 0; i--) {
			a2.add((s2.charAt(i) - '0'));
		}

		//模拟乘以的过程
		for (int i = 0; i < a1.size(); i++) {
			for (int j = 0; j < a2.size(); j++) {
				if (res.get(i + j) == -1) {
				//如果要访问,就把-1变为0
					res.set(j + i, 0);
				}
				res.set(j + i, res.get(i + j) + (a1.get(i) * a2.get(j)));

			}
		}

		//进位处理
		int up = 0;
		int cnt = 0;
		while (res.get(cnt) != -1) {
			int temp = res.get(cnt) + up;
			up = temp / 10;
			res.set(cnt, temp % 10);
			cnt++;
		}
		if (up != 0) {
			res.set(cnt, up % 10);
			up /= 10;
			cnt++;
		}

		//如果最高位为0,就要取出,但要保证至少有一位数
		while (res.get(cnt-1)==0&&cnt>1) {
			cnt--;
		}
		for (int i = cnt - 1; i >= 0; i--) {
				System.out.print(res.get(i));
			
		}
	}
}


阶乘之和(传送门)

题目描述
用高精度计算出 S = 1! + 2! + 3! +…+ n! 1≤50n≤50)。
其中“!”表示阶乘,例如:5!=5×4×3×2×1。
输入格式
一个正整数 n。
输出格式
一个正整数 S,表示计算结果。
输入输出样例
输入 #1
输出 #1
9
说明/提示
【数据范围】
对于 100 % 的数据,1 ≤n≤50。
思路差不多,这里给出AC代码就行了,就是高精度加法和乘法的组合。

AC代码:

import java.util.ArrayList;
import java.util.Scanner;

public class P1009 {
    public static void main(String[] args) {
    	ArrayList<Integer> res =new ArrayList<>();
    	ArrayList<Integer> temp =new ArrayList<>();
    	res.add(1);
    	temp.add(1);
    	for (int i = 0; i < 2000; i++) {
    		res.add(0);
    		temp.add(0);
		}
		Scanner sc =new Scanner(System.in);
		int n=sc.nextInt();
		int res_cnt=1,temp_cnt=1;
		for (int i = 2; i <= n; i++) {
			//所有位都×上
			for (int j = 0; j < temp_cnt; j++) {
				temp.set(j, temp.get(j)*i);
			}
			//进位处理操作
			int up=0;
			for (int j = 0; j < temp_cnt; j++) {
				int x=temp.get(j)+up;
				temp.set(j, x%10);
				up=x/10;
			}
			while (up!=0) {
				temp.set(temp_cnt, up%10);
				up/=10;
				temp_cnt++;
			}
			//加入到结果中
			up=0;
			int cnt=0;
			while (cnt<temp_cnt||cnt<res_cnt) {
				int x =res.get(cnt)+temp.get(cnt)+up;
				res.set(cnt, x%10);
				up=x/10;
				cnt++;
			}
			if (up!=0) {
				res.set(cnt, up);
				cnt++;
			}
			res_cnt=cnt;
		}
		for (int i = res_cnt-1; i >=0; i--) {
			System.out.print(res.get(i));
		}
	}
}

(3)日期模拟

日期问题想必大家都做过,这里给三个小技巧或有关时间的算法,帮助轻松解题。

基穆拉二森公式:

可以通过年月日快速计算出这一天是星期几

public static int WeekDay(int y, int m, int d) {//判断星期的函数
        return (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400 + 1) % 7+1;
    }

判断闰年

 	public static boolean IsLeapYear(int year) {
        if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
            return true;
        } else return false;
    }

日期的存储:

使用二维数组存储,多开一个空间,这样访问数组下标就不麻烦了

int[][] stanrd_year = {
                //二维数组,开13个空间,方便取出数,stanrd_year[][0]普通年,
                // stanrd_year[][1]闰年
                {0, 0},
                {31, 31}, {28, 29}, {31, 31}, {30, 30}, {31, 31}, {30, 30},
                {31, 31}, {31, 31}, {30, 30}, {31, 31}, {30, 30}, {31, 31},
        };

下面给出两个真题

十一届蓝桥杯第二次省赛C/C++组B组 试题 D: 跑步锻炼

本题总分:10 分
【问题描述】
小蓝每天都锻炼身体。
正常情况下,小蓝每天跑 1 千米。如果某天是周一或者月初(1 日),为了
激励自己,小蓝要跑 2 千米。如果同时是周一或月初,小蓝也是跑 2 千米。
小蓝跑步已经坚持了很长时间,从 2000 年 1 月 1 日周六(含)到 2020 年
10 月 1 日周四(含)。请问这段时间小蓝总共跑步多少千米?
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

答案:8879

AC代码:

package 算法小结.时间;

/**
 * Created by IntelliJ IDEA.
 * User: ShiYu Huang
 * Date: 2021/2/12
 */
public class 跑步锻炼 {
    public static int WeekDay(int y, int m, int d) {//判断星期的函数
        return (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400 + 1) % 7+1;
    }

    public static int IsLeapYear(int year) {
        if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
            return 1;
        } else return 0;
    }

    public static void main(String[] args) {

        int[][] stanrd_year = {
                //二维数组,开13个空间,方便取出数,stanrd_year[][0]普通年,
                // stanrd_year[][1]闰年
                {0, 0},
                {31, 31}, {28, 29}, {31, 31}, {30, 30}, {31, 31}, {30, 30},
                {31, 31}, {31, 31}, {30, 30}, {31, 31}, {30, 30}, {31, 31},
        };
        int y = 2000, m = 1, d = 1;//初始的时间
        int r = 1;//初始的年份是2020
        int cnt = 0;//计数器
        while (true) {
            //判断部分
            if (d == 1 || WeekDay(y, m, d) == 1) {
                //满足一个条件即可,一个月的首天或星期一,使用||不会取重复
                cnt += 2;
            } else {
                cnt++;
            }

            //时间更新部分
            d++;
            if (d == stanrd_year[m][r] + 1) {//统计完一个月的最后一天
                d = 1;
                m++;
            }
            if (m == 13) {//统计完一年的最后一天
                m = 1;
                y++;
                r = IsLeapYear(y);//更新是否是闰年的记录
            }

            //退出条件,注意边界问题哈,不要送分题白给了啊!
            if (y == 2020 && m == 10 && d == 2) {
                break;
            }
        }
        System.out.println(cnt);
    }
}


十一届蓝桥杯第二次省赛C/C++组B组 试题 G: 回文日期

时间限制: 1.0s 内存限制: 256.0MB 本题总分:20 分
【问题描述】
2020 年春节期间,有一个特殊的日期引起了大家的注意:2020 年 2 月 2
日。因为如果将这个日期按 “yyyymmdd” 的格式写成一个 8 位数是 20200202,
恰好是一个回文数。我们称这样的日期是回文日期。
有人表示 20200202 是 “千年一遇” 的特殊日子。对此小明很不认同,因为
不到 2 年之后就是下一个回文日期:20211202 即 2021 年 12 月 2 日。
也有人表示 20200202 并不仅仅是一个回文日期,还是一个 ABABBABA
型的回文日期。对此小明也不认同,因为大约 100 年后就能遇到下一个
ABABBABA 型的回文日期:21211212 即 2121 年 12 月 12 日。算不上 “千
年一遇”,顶多算 “千年两遇”。
给定一个 8 位数的日期,请你计算该日期之后下一个回文日期和下一个
ABABBABA 型的回文日期各是哪一天。
【输入格式】
输入包含一个八位整数 N,表示日期。
【输出格式】
输出两行,每行 1 个八位数。第一行表示下一个回文日期,第二行表示下
一个 ABABBABA 型的回文日期。
【样例输入】
20200202
【样例输出】
20211202
21211212
【评测用例规模与约定】
对于所有评测用例,10000101 ≤ N ≤ 89991231,保证 N 是一个合法日期的
8 位数表示。

AC代码:

package 算法小结.时间;

import java.util.Scanner;

/**
 * Created by IntelliJ IDEA.
 * User: ShiYu Huang
 * Date: 2021/2/12
 */
public class 回文时间 {
    //一样的逻辑,只不过我们用数组来存储时间更容易我们判断(递归判断回文)
    public static boolean IsReverse(int a[], int left, int right) {
        while (left <= right) {
            if (a[left] != a[right]) return false;
            else return IsReverse(a, left + 1, right - 1);
        }
        return true;
    }

    public static int LeapYear(int year) {
        if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
            return 1;
        } else return 0;
    }

    public static void main(String[] args) {
        int[][] stanrd_year = {
                //二维数组,开13个空间,方便取出数,stanrd_year[][0]普通年,
                // stanrd_year[][1]闰年
                {0, 0},
                {31, 31}, {28, 29}, {31, 31}, {30, 30}, {31, 31}, {30, 30},
                {31, 31}, {31, 31}, {30, 30}, {31, 31}, {30, 30}, {31, 31},
        };
        int flag01 = 0, flag02 = 0;//判断是否已经找到了回文串与特殊回文串。
        int[] time = new int[8];//保存时间的数组
        Scanner sc = new Scanner(System.in);//输入数据
        int n = sc.nextInt();
        for (int i = 7; i >= 0; i--) {//将初始时间存入数组中.
            time[i] = n % 10;
            n /= 10;
        }
        int r = LeapYear(time[0] * 1000 + time[1] * 100 + time[2] * 10 + time[3]);
        while (flag01 == 0 || flag02 == 0) {
            //时间更新函数
            time[7]++;
            if (time[7] == 10) {//day进位
                time[6]++;
                time[7] = 0;
            }
            if (time[6] * 10 + time[7] == stanrd_year[time[4] * 10 + time[5]][r] + 1) {
                //一个月的最后一天
                time[6] = 0;
                time[7] = 1;
                time[5]++;
            }
            if (time[5] == 10) {//month进位
                time[4]++;
                time[5] = 0;
            }
            if (time[4] * 10 + time[5] == 13) {
                //一年的最后一天被取完
                time[4] = 0;
                time[5] = 1;
                time[3]++;
            }
            //检查年份的格式
            for (int i = 3; i >= 1; i--) {
                if (time[i] == 10) {
                    time[i] = 0;
                    time[i - 1]++;
                }
            }

            //格式正确,可以开始检查时间是不是回文时间啦!
            if (flag01 == 0) {//普通回文日期的判断
                if (IsReverse(time, 0, 7)) {
                    flag01 = 1;
                    for (int i = 0; i < time.length; i++) {
                        System.out.print(time[i]);
                    }
                    System.out.println();
                }
            }
            if (flag02 == 0) {//ABABBABA型的回文日期判断条件
                if (time[0] != time[1] &&
                        time[0] == time[2] && time[2] == time[5] && time[5] == time[7]
                        && time[1] == time[3] && time[3] == time[4] && time[4] == time[6]) {
                    flag02 = 1;
                    for (int i = 0; i < time.length; i++) {
                        System.out.print(time[i]);
                    }
                    System.out.println();
                }
            }
        }
    }
}


习题清单

简单模拟:

十一届蓝桥杯第二次省赛C/C++组B组 试题 C: 蛇形填数

本题总分:10 分
【问题描述】
如下图所示,小明用从 1 开始的正整数“蛇形”填充无限大的矩阵。
1 2 6 7 15 …
3 5 8 14 …
4 9 13 …
10 12 …
11 …

容易看出矩阵第二行第二列中的数是 5。请你计算矩阵中第 20 行第 20 列
的数是多少?
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。


版权声明:本文为huangshiyu123456原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。