1. 程式人生 > 其它 >藍橋杯日期模擬類問題總結

藍橋杯日期模擬類問題總結

日期模擬幾乎是藍橋杯每年的必考題目,所以總結一下往年題目

【第八屆】【省賽】日期問題

【問題描述】

小明正在整理一批歷史文獻。這些歷史文獻中出現了很多日期。小明知道這些日期都在1960年1月1日至2059年12月31日。令小明頭疼的是,這些日期採用的格式非常不統一,有采用年/月/日的,有采用月/日/年的,還有采用日/月/年的。更加麻煩的是,年份也都省略了前兩位,使得文獻上的一個日期,存在很多可能的日期與其對應。

  比如02/03/04,可能是2002年03月04日、2004年02月03日或2004年03月02日。

  給出一個文獻上的日期,你能幫助小明判斷有哪些可能的日期對其對應嗎?

【輸入格式】

一個日期,格式是"AA/BB/CC"。 (0 <= A, B, C <= 9)

【輸入格式】

輸出若干個不相同的日期,每個日期一行,格式是"yyyy-MM-dd"。多個日期按從早到晚排列。

【樣例輸入】

02/03/04

樣例輸出

2002-03-04
2004-02-03
2004-03-02

#include<bits/stdc++.h>
using namespace std;

int days[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

bool cheak(int yy, int mm, int dd) {
	if (mm == 0 || mm > 12) return false;
	if (dd == 0) return false;
	if (mm == 2) {
		int leap = (yy % 4 == 0 && yy % 100) || (yy % 400 == 0);
		if (dd > days[mm] + leap) return false;
	} else {
		if (dd > days[mm]) return false;
	}
	return true;
}

int main()
{
    int a, b, c;
    scanf("%d/%d/%d", &a, &b, &c);
	for (int i = 19600101; i <= 20591231; i ++) {
		int yy = i / 10000, mm = i % 10000 / 100, dd = i % 100;
		if (cheak(yy, mm, dd)) {
			if (yy%100 == a && mm == b && dd == c) {
				printf("%d-%02d-%02d\n", yy, mm, dd);
			} else if (yy%100 == c && mm == a && dd == b) {
				printf("%d-%02d-%02d\n", yy, mm, dd);
			} else if (yy%100 == c && mm == b && dd == a) {
				printf("%d-%02d-%02d\n", yy, mm, dd);
			}
		}
	}
    
    return 0;
}

【第十一屆】【省賽】【迴文日期】

【問題描述】

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

#include<bits/stdc++.h>
using namespace std;

int day[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

bool check (int yy, int mm, int dd) {
	if (!dd) return false;
	if (!mm || mm > 12) return false;
	int leap = (yy % 4 == 0 || yy % 100) || (yy % 400 == 0);
	if (mm == 2) {
		if (dd > day[mm] + leap) return false;
	} else {
		if (dd > day[mm]) return false;
	}
	return true;
}

bool huiwen(string s) {
	for (int i = 0, j = s.size()-1; i < j; i ++, j --) {
		if (s[i] != s[j]) return false;
	}
	return true;
}

bool ty(string s) {
	if (s[0] == s[1]) return false;
	char a = s[0], b = s[1];
	for (int i = 0; i < s.size(); i ++) {
		if (s[i] == a) s[i] = 'A';
		if (s[i] == b) s[i] = 'B';
	}
	if (s == "ABABBABA") return true;
	else return false;
}

int main()
{
	int n;
	cin >> n;
	int flag = 0;
	for (int i = n + 1; ; i ++) {
		int yy = i / 10000, mm = i % 10000 / 100, dd = i % 100;
		if (check(yy, mm, dd)) {
			string s;
			int k = i;
			while (k) {
				int x = k % 10;
				s += x+'0';
				k /= 10;
			}
			if (huiwen(s) && !flag) {
				cout << s << endl;
				flag = 1;
			}
			if (ty(s)) {
				cout << s;
				break;
			}
		}
	}
	return 0;
}

小結

通過上面兩道題可以看出一個大致的套路都是通過暴力遍歷每一個整數然後判斷這個整數是否是一個正確的日期,總結為以下模板

int day[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

bool check (int yy, int mm, int dd) {
	if (!dd) return false;
	if (!mm || mm > 12) return false;
	int leap = (yy % 4 == 0 || yy % 100) || (yy % 400 == 0);
	if (mm == 2) {
		if (dd > day[mm] + leap) return false;
	} else {
		if (dd > day[mm]) return false;
	}
	return true;
}