在此为读者写了几个扣分点,不得不说这是近几年最麻烦的一道大模拟,也是最近做的最爽的大模拟,打着打着就两百行了。
先来看下改了多少次
1. 英文缩写不区分大小写 (10分)
2. 数组大小没开够 (20分)
3. 可能存在区间的重合 例如: 0,0-5 但是0只输出一次
4. 同时发生的按照输入顺序排序
5. s取,t不取
题目大意:
给n个行为的运行时间,包括月,日,星期几,时间,分钟。给定起始时间和终止时间,打印程序的运行表。
题目思路:
首先最简单的方法是一分钟一分钟的往后推移,但是计算时间复杂度的话 总分钟数 = 130年 * 365 天 * 24 小时 * 60分钟 = 6e7
好像可行,但是我们发现他保证输出只有不超过10000行,模拟分钟的话有点小题大做。所以我们打算一天一天往后推移。
所以
1. 预处理出每条命令允许在哪天哪月哪分钟哪小时哪礼拜可行。
2. 遍历每一天,把改天内的所有符合条件的输出存入结构体node。
3. 排序输出 ,第一优先级是小时,第二优先级是分钟,第三优先级是id。
首先做个预处理:
定义以下数组:
int d[25][35]; ///d [i][j] 表示第i条命令,在哪那天允许 1-31
int y[25][15]; ///y [i][j] 表示第i条命令,在哪天月 1-12
int wk[25][10]; ///wk [i][j] 表示第i条命令,在哪礼拜允许 0-6
set<int>fen[25],shi[25]; ///fen[i]表示第i条命令分钟的集合,shi[i]表示第i条命令小时的集合
string yy[15] = {"","jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"};
///匹配月和周的英文
string ww[15] = {"sun","mon","tue","wed","thu","fri","sat"};
fen,shi用set是因为存在区间重叠的情况。
调用fun()分离,分隔得内容,ss-ee,然后调用character 把ss,ee转化为数字,然后根据flag在相应的数组上标记。
然后遍历每一天:
如果是起始的或终止的那一天,要查看是否迟于起始早于结束。如果是普通的一天,就把全部的小时,分钟组合存起来,
记住同时要把id存入,作为第三优先级。
然后就是跳天数:
判断是闰年还是平年,然后一天一天往后跳就可以了。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN = 1e5+5;
int d[25][35]; ///d [i][j] 表示第i条命令,在哪那天允许 1-31
int y[25][15]; ///y [i][j] 表示第i条命令,在哪天月 1-12
int wk[25][10]; ///wk [i][j] 表示第i条命令,在哪礼拜允许 0-6
set<int>fen[25],shi[25]; ///fen[i]表示第i条命令分钟的集合,shi[i]表示第i条命令小时的集合
string yy[15] = {"","jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec"};
string ww[15] = {"sun","mon","tue","wed","thu","fri","sat"};
string ffun[25];
int run[20]={0,31,29,31,30,31,30,31,31,30,31,30,31};
int pin[20]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int n;
ll st,ed;
struct node ///暂时存答案排序
{
int y,m,d,h,f;
int id;
}C[MAXN];
int week(int year,int mon,int day){ ///日期转化礼拜几
if(mon == 1||mon == 2)
mon+=12,year --;
int w=(day+2*mon+3*(mon+1)/5+year+year/4-year/100+year/400+1)%7;
return w;
}
void character(string ss,string ee,int flag,int i) ///把ss-ee的范围标记
{
//cout<<ss<<" + "<<ee<<endl;
int s1 = 0,s2 = 0;
for(int j=0;j<ss.size();j++){
if(ss[j]>='A' && ss[j]<='Z')ss[j]=ss[j]-'A'+'a';
}
for(int j=0;j<ee.size();j++){
if(ee[j]>='A' && ee[j]<='Z')ee[j]=ee[j]-'A'+'a';
}
if(ss[0]>='a'&&ss[0]<='z'){
if(flag == 4){
for(int j=1;j<=12;j++){
if(ss == yy[j])
s1 = j;
}
}
if(flag == 5){
for(int j=0;j<7;j++){
if(ss == ww[j])
s1 = j;
}
}
}
else {
for(int j=0;j<ss.size();j++)
s1 = s1*10+(ss[j]-'0');
}
if(ee[0]>='a' && ee[0]<='z'){
if(flag == 4){
for(int j=1;j<=12;j++){
if(ee == yy[j])
s2 = j;
}
}
if(flag == 5){
for(int j=0;j<7;j++){
if(ee == ww[j])
s2 = j;
}
}
}
else{
for(int j=0;j<ee.size();j++)
s2 = s2*10+(ee[j]-'0');
}
if(flag == 1){ ///flag1,2,3,4,5分别代表输入顺序
for(int j=s1;j<=s2;j++)
fen[i].insert(j);
}
if(flag == 2){
for(int j=s1;j<=s2;j++)
shi[i].insert(j);
}
if(flag == 3){
for(int j=s1;j<=s2;j++)
d[i][j] = 1;
}
if(flag == 4){
for(int j=s1;j<=s2;j++)
y[i][j] = 1;
}
if(flag == 5){
for(int j=s1;j<=s2;j++)
wk[i][j] = 1;
}
}
void fun(string s,int flag,int i) ///分离ss 和 ee
{
string ss = "",ee = "";
bool f = 0;
int len = s.size();
for(int j=0;j<=len;j++){
if(s[j] == '-'){
f = 1;continue; ///变更开关往e里输入
}
if(s[j] == ','||j == len){
if(f == 0)ee = ss; ///如果没横线那么就表示单个数字ss==ee
character(ss,ee,flag,i);
ss = "",ee = "",f = 0;
}
if(s[j]!='-' && s[j]!=','){
if(!f)
ss += s[j];
else ee += s[j];
}
}
}
void inpt()
{
for(int i=1;i<=n;i++){
string s;
cin>>s; ///输入分钟
if(s == "*"){
for(int j=0;j<=59;j++)
fen[i].insert(j);
}
else fun(s,1,i);
cin>>s; ///输入小时
if(s == "*"){
for(int j=0;j<=23;j++){
shi[i].insert(j);
}
}
else fun(s,2,i);
cin>>s; ///输入日
if(s == "*"){
for(int j = 1;j<=31;j++)
d[i][j] = 1;
}
else fun(s,3,i);
cin>>s; ///输入月
if(s == "*"){
for(int j=1;j<=12;j++)
y[i][j] = 1;
}
else fun(s,4,i);
cin>>s; ///输入周
if(s == "*"){
for(int j=0;j<=6;j++)
wk[i][j] = 1;
}
else fun(s,5,i);
cin>>ffun[i];
}
}
int s_y,s_m,s_d,s_h,s_f;
int e_y,e_m,e_d,e_h,e_f;
bool cmp(node a,node b) ///排序答案
{
if(a.h == b.h){
if(a.f == b.f){
return a.id<b.id;
}
return a.f<b.f;
}
return a.h<b.h;
}
void tackle(int ny,int nm,int nd,int nwk)
{
int tot = 0 ;
for(int i=1;i<=n;i++){
if(d[i][nd] == 1 && y[i][nm] == 1 && wk[i][nwk] == 1){
set<int>::iterator j ;
set<int>::iterator k ;
for(j = fen[i].begin();j!=fen[i].end();j++){
for(k = shi[i].begin();k!=shi[i].end();k++){
int ff = (*j);
int ss = (*k);
bool f = 1;
if(ny == s_y && nm == s_m && nd == s_d){
if(ss*60+ff < s_h*60+s_f)f = 0;
}
if(ny == e_y && nm == e_m && nd == e_d){
if(ss*60+ff >= e_h*60+e_f)f = 0;
}
if(f){
C[++tot].y = ny;C[tot].m = nm;C[tot].d = nd;
C[tot].h = ss;C[tot].f = ff;C[tot].id = i;
}
}
}
}
}
sort(C+1,C+1+tot,cmp);
for(int i=1;i<=tot;i++){
printf("%04d",C[i].y);
printf("%02d",C[i].m);
printf("%02d",C[i].d);
printf("%02d",C[i].h);
printf("%02d",C[i].f);
cout<<" "<<ffun[C[i].id]<<endl;
}
}
bool is_run(int x)
{
if(x%400 == 0)return 1;
if(x%4==0&&x%100!=0)return 1;
return 0;
}
int main()
{
cin>>n;
cin>>st>>ed;
inpt();
s_f = st%100; st/=100; s_h = st%100; st/=100;
s_d = st%100; st/=100; s_m = st%100; st/=100;
s_y = st;
int s_wk = week(s_y,s_m,s_d);
e_f = ed%100; ed/=100; e_h = ed%100; ed/=100;
e_d = ed%100; ed/=100; e_m = ed%100; ed/=100;
e_y = ed;
int n_y = s_y,n_m = s_m,n_d = s_d;
while(n_y != e_y || n_m != e_m || n_d != e_d){
tackle(n_y,n_m,n_d,s_wk);
s_wk = (s_wk+1)%7;
if(is_run(n_y)){ ///跳日期
if(n_d == run[n_m]){
n_d = 1;
n_m ++;
}
else n_d++;
}
else{
if(n_d == pin[n_m]){
n_d = 1;
n_m ++;
}
else n_d++;
}
if(n_m == 13){
n_y++;
n_m = 1;
}
}
tackle(e_y,e_m,e_d,s_wk);
}
/*
3 201711170032 201711222352
0,0 7 * * 1,3-5 get_up
30 23 * * Sat,Sun go_to_bed
15 12,18 * * * have_dinner
3 201711170032 201711222352
0 7 * * 1,3-fri get_up
30 23 * * Sat,Sun go_to_bed
15 12,18 * * * have_dinner
*/
///区间重叠
///数组大小
///年月日缩写(不分大小写)
///时间排序
///s取t不取