3214. 节日
有一类节日的日期并不是固定的,而是以“a 月的第 b 个星期 c ”的形式定下来的,比如说母亲节就定为每年的五月的第二个星期日。
现在,给你 a,b,c 和 y1,y2,希望你输出从公元 y1 年到公元 y2 年间的每年的 a 月的第 b 个星期 c 的日期。
提示:关于闰年的规则:年份是 400 的整数倍时是闰年,否则年份是 4 的倍数并且不是 100 的倍数时是闰年,其他年份都不是闰年。
例如 1900 年就不是闰年,而 2000 年是闰年。
为了方便你推算,已知 1850 年 1 月 1 日是星期二。
输入格式
输入包含恰好一行,有五个整数 a,b,c,y1,y2。
其中 c=1,2,……,6,7 分别表示星期一、二、……、六、日。
输出格式
对于 y1 和 y2 之间的每一个年份,包括 y1 和 y2,按照年份从小到大的顺序输出一行。
如果该年的 a 月第 b 个星期 c 确实存在,则以
yyyy/mm/dd
的格式输出,即输出四位数的年份,两位数的月份,两位数的日期,中间用斜杠/
分隔,位数不足时前补零。如果该年的 a 月第 b 个星期 c 并不存在,则输出
none
。
#include <bits/stdc++.h>
using namespace std;
int months[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
//将月份与天数对应
int is_leap(int y) //如果当前年为闰年返回1,否则返回0
{
if (y % 400 == 0 || y % 4 == 0 && y % 100) return 1;
return 0;
}
int get_days(int y, int m) //返回当前月共有多少天
{
if (m == 2) return months[m] + is_leap(y);
return months[m];
}
int main()
{
int a, b, c, y1, y2;
cin >> a >> b >> c >> y1 >> y2;
int days = 0; //记录当前天距离1850.1.1有多少天
for (int y = 1850; y <= y2; y ++)
for (int m = 1; m <= 12; m ++)
{
if (y >= y1 && m == a) //到所求月份
{
int w = (1 + days) % 7, cnt = 0; //w为当前月第一天的星期几
//注1850.1.1是星期二,所以加1
for (int d = 1; d <= get_days(y, m); d ++)
{
if (w == c - 1) //0,1,2,,,6分别表示星期1到7
{
cnt ++;
if (cnt == b)
{
printf("%04d/%02d/%02d\n", y, m, d);
break;
}
}
w = (w + 1) % 7;
}
if (cnt < b) puts("none");
}
days += get_days(y, m);
}
return 0;
}
3254. Crontab
Cron (源自希腊语 χρόνοςχρόνος,意思是时间〉是类 Unix 系统下基于时间的任务调度器,用于在固定的时间运行指定的任务(多为系统管理和维护的任务)。
Cron 适合于周期性重复调度的任务,通过crontab文件来描述调度任务的配置。
Crontab文件由若干行组成,每行是一条配置信息,格式如下:
<minutes> <hours> <day of month> <month> <day of week> <command>
表示在满足前 5 项所指定的时间来运行第 6 项
<command>
所描述的命令。前 55 项用于描述时间,含义和取值范围如下:
<minutes>
是分钟数,取值范围是 0−59;<hours>
是小时数,取值范围是 0−23;<day of month>
是月份中的天数,取值范围是 1−31;<month>
是月份,取值范围是 1−12,或Jan
-Dec
;<day of week>
是星期几,取值范围是 0−6,或Sun
-Sat
。对于前 5 项,除了可以直接给出数字或者英文缩写(不区分大小写)外,还可以出现星号
*
(表示任何取值)、逗号,
(表示多个不同的取值)或减号-
(表示一段连续的取值范围)。星号只能单独出现,减号和逗号可以配合出现。
Cron 每分钟检查一次系统时间,当系统时间同时满足这 5 项要求时,cron 将执行对应的命令。
给出一个时间段,以及一个 crontab 文件,请你编程输出在这段时间内的任务调度执行情况。
输入格式
输入第一行有 33 个整数 n、s、t,用空格分隔。n 表示接下来有 n 行,描述一个 crontab 文件。s 和 t 分别为系统运行的开始时间(包含)和结束时间(不包含),格式为
yyyymmddHHMM
(年、月、日、小时、分钟)。接下来有 n 行,每行是一条 crontab 配置信息,相邻两项之间用一个空格分隔。
输出格式
输出有若干行,每行表示一个任务调度,由两部分构成︰第一部分是任务调度的时间,格式同样为
yyyymmddHHMM
,第二部分是调度执行的命令。两部分之间用一个空格分隔。
按照时间先后顺序输出。
如果同一时刻有多条命令满足调度条件,则按照输入给出的顺序输出。
数据范围
输入数据约定:
- 1≤n≤20,s≤t
- 输入数据中给出的时间均在
1970-01-01 00:00
到2099-12-31 23:59
之间。- 输入中给出的命令只包含大小写字母、数字和下划线
_
,不包含空格或其他符号。- 保证输入中描述时间的部分都是合法的。对于减号描述的时间范围 x−y,一定满足 x≤y。英文缩写的拼写保证是正确的。英文缩写和数值可以混合使用。分钟数和小时数可以有前导 0,也可以没有(例如,00 和 0 都是合法的输入),其他部分不会出现前导 0。
- 输入的每行不超过 100 个字符。
- 保证输出内容不超过 10000 行。
- 提示:1970 年 1 月 1 日是星期四。
输入数据特征(√ 表示可以出现,× 表示不会出现)∶
附:月份与星期的英文缩写对照表:
输入样例:
3 201711170032 201711222352 0 7 * * 1,3-5 get_up 30 23 * * Sat,Sun go_to_bed 15 12,18 * * * have_dinner
输出样例:
201711170700 get_up 201711171215 have_dinner 201711171815 have_dinner 201711181215 have_dinner 201711181815 have_dinner 201711182330 go_to_bed 201711191215 have_dinner 201711191815 have_dinner 201711192330 go_to_bed 201711200700 get_up 201711201215 have_dinner 201711201815 have_dinner 201711211215 have_dinner 201711211815 have_dinner 201711220700 get_up 201711221215 have_dinner 201711221815 have_dinner
样例解释
样例输入给出了 3 条 cron 配置信息,系统运行的开始时间是
2017-11-17 00:32
(包含),结束时间为2017-11-22 23:52
(不包含)。每条配置信息的含义如下:
1.在星期一、三、四、五的 7 点整运行get_up
命令。
2.在星期六、星期天的 23 点 30 分运行go_to_bed
命令。
3.在每天的 12 点 15 分和 18 点 15 分运行have_dinner
命令。
#include <bits/stdc++.h>
using namespace std;
int n;
int months[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
struct Timer
{
int year, month, day, hour, minute, week;
Timer(string str)
{
sscanf(str.c_str(), "%04d%02d%02d%02d%02d", &year, &month, &day, &hour, &minute);
//c_str() 将const string*类型 转化为const char*类型
}
bool operator< (const Timer &t)const //set
{
if (year != t.year) return year < t.year;
if (month != t.month) return month < t.month;
if (day != t.day) return day < t.day;
if (hour != t.hour) return hour < t.hour;
return minute < t.minute;
}
int is_leap()
{
if (year % 400 == 0 || (year % 100 && year % 4 == 0)) return 1;
return 0;
}
int get_days()
{
if (month == 2) return months[2] + is_leap();
return months[month];
}
void next()
{
if (++ minute == 60)
{
minute = 0;
if (++ hour == 24)
{
week = (week + 1) % 7;
hour = 0;
if (++ day > get_days())
{
day = 1;
if (++ month == 13)
{
month = 1;
year ++;
}
}
}
}
}
string to_string()
{
char str[20];
sprintf(str, "%04d%02d%02d%02d%02d", year, month, day, hour, minute);
return str;
}
};
struct Task
{
bool minutes[60], hours[24], day_of_month[32], month[13], day_of_week[7];
string name;
bool check(Timer &t)
{
return minutes[t.minute] && hours[t.hour] && day_of_month[t.day] &&
month[t.month] && day_of_week[t.week];
}
}task[20];
unordered_map<string, int> nums;
void init() //将月份及星期的英文表达与其值对应起来
{
//注意 0-6分别为星期天到星期六
string key[] = {
"jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec",
"sun", "mon", "tue", "wed", "thu", "fri", "sat"
};
int value[] = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
0, 1, 2, 3, 4, 5, 6
};
for (int i = 0; i < 19; i ++)
nums[key[i]] = value[i];
}
int get(string str) //将其字符串转换为它所表达的数值
{
if (str[0] <= '9' && str[0] >= '0') return stoi(str);
string s;
for (auto c: str) s += tolower(c);
return nums[s];
}
void work(string str, bool st[], int len) //标记当前任务数组是否在范围内
{
if (str == "*")
{
for (int i = 0; i < len; i ++) st[i] = true;
}
else
{
for (int i = 0; i < str.size(); i ++)
{
int j = i + 1;
while (j < str.size() && str[j] != ',') j ++;
string s = str.substr(i, j - i);
i = j;
int k = s.find('-');
if (k != -1)
{
int l = get(s.substr(0, k)), r = get(s.substr(k + 1));
for (int u = l; u <= r; u ++) st[u] = true;
}
else st[get(s)] = true;
}
}
}
int main()
{
init();
string st, ed;
cin >> n >> st >> ed;
for (int i = 0; i < n; i ++)
{
string minutes, hours, day_of_month, month, day_of_week, name;
cin >> minutes >> hours >> day_of_month >> month >> day_of_week >> name;
work(minutes, task[i].minutes, 60);
work(hours, task[i].hours, 24);
work(day_of_month, task[i].day_of_month, 32);
work(month, task[i].month, 13);
work(day_of_week, task[i].day_of_week, 7);
task[i].name = name;
}
Timer t("197001010000"), S(st), E(ed); //t为题目给出的日期,当前为星期四
t.week = 4;
while (t < E)
{
if (!(t < S)) //注意只重载了小于号 所以>=用!<表示
{
for (int i = 0; i < n; i ++)
if (task[i].check(t))
cout << t.to_string() << " " << task[i].name << endl;
}
t.next(); //下一天
}
return 0;
}