201712-3 CSP认证 Crontab (大模拟-详细解析100分)

      在此为读者写了几个扣分点,不得不说这是近几年最麻烦的一道大模拟,也是最近做的最爽的大模拟,打着打着就两百行了。

先来看下改了多少次

                            

 

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不取

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值