排序
#include <iostream>
#include <algorithm>
using namespace std;
bool cmp(int x, int y) { // 定义排序规则
return x > y;
}
int main() {
int n;
int buf[100];
while (scanf("%d", &n) != EOF) {
for (int i = 0; i < n; i++) {
scanf("%d", &buf[i]);
}
sort(buf, buf+n, cmp); // 使用该重载形式,我们表明将要使用自己定义的排列规则
for (int i = 0; i < n; i++) {
printf("%d " , buf[i]);
}
printf("\n");
}
return 0;
}
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
struct E {
char name[101];
int age;
int score;
} buf[1000];
bool cmp(E a, E b) { // 定义排序规则
if (a.score != b.score) return a.score < b.score; // 若分数不相同则分数低者在前
int tmp = strcmp(a.name, b.name);
if (tmp != 0)
return tmp < 0; // 若分数相同则名字字典序小者在前
else return a.age < b.age; // 若名字也相同则年龄小者在前
}
int main() {
int n;
while (scanf("%d", &n) != EOF) {
for (int i = 0; i < n; i++) {
scanf("%s%d%d", buf[i].name, &buf[i].age, &buf[i].score);
}
sort(buf, buf+n, cmp); // 使用自己定义的规则排序
for (int i = 0; i < n; i++) {
printf("%s %d %d\n" , buf[i].name, buf[i].age, buf[i].score);
}
}
return 0;
}
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
struct E {
char name[101];
int age;
int score;
bool operator < (const E& b) const { // 利用C++运算符重载直接定义小于号
if (score != b.score) return score < b.score; // 若分数不相同则分数低者在前
int tmp = strcmp(name, b.name);
if (tmp != 0)
return tmp < 0; // 若分数相同则名字字典序小者在前
else return age < b.age; // 若名字也相同则年龄小者在前
}
} buf[1000];
int main() {
int n;
while (scanf("%d", &n) != EOF) {
for (int i = 0; i < n; i++) {
scanf("%s%d%d", buf[i].name, &buf[i].age, &buf[i].score);
}
sort(buf, buf+n); // 使用自己定义的规则排序
for (int i = 0; i < n; i++) {
printf("%s %d %d\n" , buf[i].name, buf[i].age, buf[i].score);
}
}
return 0;
}
日期类问题
日期差值
该例题考察了日期类问题中最基本的问题——求两个日期间的天数差,即求
分别以两个特定日期为界的日期区间的长度。
这里值得一提的是,解决这类区间问题有一个统一的思想——把原区间问题统一到起点确定的区间问题上去。在该例中,我们不妨把问题统一到特定日期与一个原点时间(如 0000 年 1 月 1 日)的天数差,当要求两个特定的日期之间的天数差时,我们只要将它们与原点日期的天数差相减,便能得到这两个特定日期之间的天数差(必要时加绝对值)。
这样做有一个巨大的好处——预处理。我们可以在程序真正开始处理输入数据之
前,预处理出所有日期与原点日期之间的天数差并保存起来。当数据真正开始输
入时,我们只需要用 O(1)的时间复杂度将保存的数据读出,稍加处理便能得
到答案。值得一提的是,预处理也是空间换时间的重要手段(保存预处理所得数
据所需的内存来换取实时处理所需要的时间消耗)。
另外,日期类问题有一个特别需要注意的要点——闰年,每逢闰年 2 月将会
有 29 天,这对我们计算天数势必会产生重大的影响。这里,我们必须明确闰年
的判断规则——当年数不能被 100 整除时若其能被 4 整除则为闰年,或者其能被
400 整除时也是闰年。用逻辑语言表达出来即为
Year % 100 != 0 && Year % 4 == 0 || Year % 400 == 0
当逻辑表达式为 true 时,其为闰年;反之则不是闰年。
从中我们也可以看出,闰年并不严格的按照四年一次的规律出现,在某种情况下也可能出现两个相邻闰年相隔八年的情况(如 1896 年与 1904 年)。所以,这里我们推荐严格按照上述表达式来判断某一年是否是闰年,而不采用某一个闰年后第四年又是闰年的规则。
#include <iostream>
int isYeap(int x) {
if ( (x % 100 != 0 && x % 4 == 0) || x % 400 == 0)
return 1;
return 0;
}
// 预存每月的天数,注意二月定义做特殊处理
int dayOfMonth[13][2] = { 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};
struct Date{ // 日期类,方便日期的推移
int Day;
int Month;
int Year;
void nextDay() {
Day++;
if (Day > dayOfMonth[Month][isYeap(Year)]) { // 若日超过了当月最大日数
Day = 1;
Month++; // 近入下一月
if (Month > 12) {
Month = 1;
Year++; // 进入下一年
}
}
}
};
int buf[5001][13][32]; // 保存预处理的天数
int Abs(int x) {
return x < 0 ? -x : x;
}
int main() {
Date tmp;
int cnt = 0; // 天数计数
tmp.Day = 1;
tmp.Month = 1;
tmp.Year = 0; // 初始化日期类对象为0年1月1日
while (tmp.Year != 5001) { // 日起不超过5000年
buf[tmp.Year][tmp.Month][tmp.Day] = cnt; // 将该日与0年1月1日的天数差保存起来
tmp.nextDay(); // 计算下一天日期
cnt++; // 计数器累加,没经过一天计数器即+1,代表与原点日期的间隔又增加一天
}
int d1, m1, y1, d2, m2, y2;
while (scanf("%4d%2d%2d", &y1, &m1, &d1) != EOF) {
scanf("%4d%2d%2d", &y2, &m2, &d2); // 读入要计算的两个日期
printf("%d\n", Abs(buf[y2][m2][d2] - buf[y1][m1][d1]) + 1);
}
return 0;
}
#include <iostream>
#include <cstdio>
#include <cstring>
int isYeap(int x) {
if ( (x % 100 != 0 && x % 4 == 0) || x % 400 == 0)
return 1;
return 0;
}
// 预存每月的天数,注意二月定义做特殊处理
int dayOfMonth[13][2] = { 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};
struct Date{ // 日期类,方便日期的推移
int Day;
int Month;
int Year;
void nextDay() {
Day++;
if (Day > dayOfMonth[Month][isYeap(Year)]) { // 若日超过了当月最大日数
Day = 1;
Month++; // 近入下一月
if (Month > 12) {
Month = 1;
Year++; // 进入下一年
}
}
}
};
int buf[3001][13][32]; // 保存预处理的天数
char monthName[13][20] = {
"", "January", "February", "March", "April", "May", "June", "July", "August",
"September", "October", "November", "December"}; // 月名,每个月名对应下标1到12
// 周名,每个周名对应下标0到6
char weekName[7][20] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
int main() {
Date tmp;
int cnt = 0; // 天数计数
tmp.Day = 1;
tmp.Month = 1;
tmp.Year = 0; // 初始化日期类对象为0年1月1日
while (tmp.Year != 3001) { // 日起不超过3000年
buf[tmp.Year][tmp.Month][tmp.Day] = cnt; // 将该日与0年1月1日的天数差保存起来
tmp.nextDay(); // 计算下一天日期
cnt++; // 计数器累加,没经过一天计数器即+1,代表与原点日期的间隔又增加一天
}
int d, m, y;
char s[20];
while (scanf("%d%s%d", &d, s, &y) != EOF) {
for (m = 1; m <= 12; m++) {
if (strcmp(s, monthName[m]) == 0)
break; // 将输入字符串与月名比较得出月数
}
int days = buf[y][m][d] - buf[2018][6][18]; // 计算给定日期与 今日日期的天数间隔(注意可能为负)
days += 1; // 今天2018.6.18为星期一,对应数组下标为1,则计算1经过days天后的下标
printf("%s", weekName[(days%7+7)%7]); // 将计算后得出的下标用7对其取模,并且保证其为非负数,则该下标即为答案所对应的下标
}
return 0;
}
Hash应用
#include <iostream>
#include <cstring>
using namespace std;
int score[105];
int main() {
int n, s;
while (scanf("%d", &n) != EOF) {
memset(score, 0, sizeof(score));
while (n--) {
cin >> s;
score[s]++;
}
cin >> s;
printf("%d\n", score[s]);
}
return 0;
}
Sort
题目描述:
给你 n 个整数,请按从大到小的顺序输出其中前 m 大的数。
输入:
每组测试数据有两行,第一行有两个数 n,m(0<n,m <1000000),第二行包含 n
个各不相同,且都处于区间[-500000,500000]的整数。
输出:
对每组测试数据按从大到小的顺序输出前 m 大的数。
样例输入:
53
3 -35 92 213 -644
样例输出:
213 92 3
#include <iostream>
#include <cstdio>
using namespace std;
const int OFFSET = 500000; // 偏移量,用于补偿实际数字与数组下标之间的偏移
int Hash[1000001]; // Hash数组,记录每个数字是否出现,不出现为0,出现后被标记为1
int main() {
int n, m;
while (scanf("%d%d", &n, &m) != EOF) {
for (int i = -500000; i <= 500000; i++) {
Hash[i+OFFSET] = 0; // 初始化,将每个数字都标记为未出现
}
for (int i = 1; i <= n; i++) {
int x;
scanf("%d", &x);
Hash[x+OFFSET] = 1; // 凡是出现过的数字,该数组元素均被设置为1
}
for (int i = 500000; i >= -500000; i--) { // 输出前m个数
if (Hash[i+OFFSET] == 1) { // 若该数字在输入中出现
printf("%d", i); // 输出该数字
m--;
if (m != 0)
printf(" ");
else {
printf("\n");
break;
}
}
}
}
return 0;
}