CCF CSP 201712-3 Crontab c++(100分)

 

做了20道ccf的t3,这道题跟带配额的文件系统绝对是最恶心的两道题了。

光敲代码敲了俩小时,debug了一个小时才过样例。好在给的样例不错,调试过样例之后提交就直接AC了,心里得到了些许安慰。

输入是n条配置信息,配置信息的格式在题目中给出了,依次是分钟,小时,天数,月份,以及星期几。可以设置一个如下结构体,代表一个任务。数组大小是5,0-4分别对应分钟,小时,天数,月份,星期几五个属性。题目中说*代表任意取值,所以all[i]为真代表可以任意取值。ele[i][j]为真代表第i个属性可以取值为j。其中分钟是60进制,所以数组大小要大于60.

name很显然是该任务的名称。

采用数组可以通过循环减少代码量。

struct TASK{

    bool all[5];

    bool ele[5][100];

    string name;

    TASK(){memset(all,false,sizeof(all));

    memset(ele,false,sizeof(ele));}

};

对于每个属性的取值,题目中说可以是'*',也可以带'-',还可以有','

其中'-'和','还可以同时出现

我采用字符串流的方式来分割字符串

首先getline读取整行,通过空格,我们可以将一行分解成六部分,前五部分是五个属性,第六部分是该任务的名字。然后处理分离得到的五个属性。此时属性可能包含'-'和',' 

我们通过将’,'替换成' ',可以再次利用字符串流分离到只带'-'或者什么也不带的属性的取值。

我们可以通过map,存储月份,星期的缩写对应的数字,题目中说不区分大小写,而且还可能有前缀零,这些都需要注意。我们map中存储的可以都是小写的,然后处理数据的时候,将英文缩写转换成小写再去查找map。

通过上述处理,我们就可以得到每个任务的可能取值。

接着就应该处理时间了,题目中提到Cron每分钟检查一次系统时间,而且时间给的是10s,不难得出,逐分钟遍历应该是不会TLE的。

怎么逐分钟遍历呢?我们可以写个函数,每小时60分钟,每天24h,每月若干天,每年12个月。每次我们(分钟+1)%60,如果结果是0,说明是新的一个小时,然后(小时+1)%24。。。后续同理,要注意判断闰年还是平年。

当当前时间处于题目给定的起始时间和结束时间之间的时候,我们对n个任务逐个判断当前时刻是否全部满足该任务的五个属性,然后进行相应的输出就可以。

完整代码如下

#include<bits/stdc++.h>

#define rep(i,start,end) for(int i=start;i<=end;i++)

using namespace std;

typedef long long LL;

typedef pair<LL,LL> pa;

int n;

int s[5],t[5];

map<string,int> dic;

bool year[2500];//是否是闰年

int m1[]={0,31,29,31,30,31,30,31,31,30,31,30,31};//每月多少天

int m2[]={0,31,28,31,30,31,30,31,31,30,31,30,31};//每月多少天

bool judge(int year)//是否是闰年

{

    if(year%400==0)return true;

    if(year%4==0&&year%100!=0)return true;

    return false;

}

void init()

{

    dic["jan"]=1,dic["feb"]=2,dic["mar"]=3,

    dic["apr"]=4,dic["may"]=5,dic["jun"]=6,

    dic["jul"]=7,dic["aug"]=8,dic["sep"]=9,

    dic["oct"]=10,dic["nov"]=11,dic["dec"]=12;

    dic["sun"]=0,dic["mon"]=1,dic["tue"]=2,dic["wed"]=3,

    dic["thu"]=4,dic["fri"]=5,dic["sat"]=6;

    for(int i=1970;i<=2100;i++)

        year[i]=judge(i);

}

struct TASK{

    bool all[5];

    bool ele[5][100];

    string name;

    TASK(){memset(all,false,sizeof(all));

    memset(ele,false,sizeof(ele));}

};

vector<TASK> task(25);

int tolow(string str)//将缩写转换成全小写

{

    bool isnum=true;

    for(auto t:str)

        if(!isdigit(t)){

            isnum=false;

            break;

        }

    if(isnum)return stoi(str);//去掉多余的前缀0

    string ans;//返回全小写的

    for(auto t:str)

        ans+=tolower(t);

    return dic[ans];

}

void solve(int x,string line)

{

    vector<string> v;

    istringstream ss(line);

    string str;

    while(ss>>str)v.push_back(str);//代表各个日期

    task[x].name=v[5];

    for(int i=0;i<5;i++){

        if(v[i]=="*"){

            //!!!插入全部的

            task[x].all[i]=true;//代表全部可以

            continue;

        }

        int index=0;

        while((index=v[i].find(',',index))!=v[i].npos){

            v[i][index]=' ';

            index++;

        }

        vector<string> date;//根据,分割后的日期

        istringstream tmpss(v[i]);

        while(tmpss>>str)date.push_back(str);//包含-的,各种写法

        for(auto t:date){

            int index=0;

            if((index=t.find('-',index))!=str.npos){//代表存在减号

                int l,r;

                l=tolow(t.substr(0,index)),r=tolow(t.substr(index+1));

                for(int j=l;j<=r;j++)

                    task[x].ele[i][j]=true;

            }

            else{//不存在减号

                task[x].ele[i][tolow(t)]=true;

            }

        }

    }

}

bool lesser(int a[],int b[])

{

    for(int i=0;i<5;i++){

        if(a[i]<b[i])return true;

        if(a[i]>b[i])return false;

    }

    return false;

}

void pluser(int a[],int &week)

{

    //加1分钟

    a[4]=(a[4]+1)%60;//分钟

    if(a[4])return ;

    a[3]=(a[3]+1)%24;//小时

    if(a[3])return ;

    week=(week+1)%7;

    if(year[a[0]]){//闰年

        if(a[2]==m1[a[1]]){//是当月最后一天

            a[2]=1;

        }

        else{

            a[2]++;

            return ;

        }

        if(a[1]==12){

            a[1]=1;

        }

        else{

            a[1]++;

            return ;

        }

        a[0]++;

    }

    else{

        if(a[2]==m2[a[1]]){//是当月最后一天

            a[2]=1;

        }

        else{

            a[2]++;

            return ;

        }

        if(a[1]==12){

            a[1]=1;

        }

        else{

            a[1]++;

            return ;

        }

        a[0]++;

    }

}

void print(int now[],string& name)

{

    for(int i=0;i<5;i++){

        if(now[i]<10)cout<<0;

        cout<<now[i];

    }

    cout<<" "<<name<<endl;

}

void func()

{

    int now[]={1970,1,1,0,0};

    int week=4;

    while(lesser(now,t)){//没到截止时间

        if(!lesser(now,s)&&lesser(now,t)){//代表在合理时间

            for(int i=1;i<=n;i++){

                if((task[i].all[0]||task[i].ele[0][now[4]])&&

                (task[i].all[1]||task[i].ele[1][now[3]])&&

                (task[i].all[2]||task[i].ele[2][now[2]])&&

                (task[i].all[3]||task[i].ele[3][now[1]])&&

                (task[i].all[4]||task[i].ele[4][week])

                )

                print(now,task[i].name);

            }

        }

        pluser(now,week);

    }

}

int main()

{

   // freopen("in.txt","r",stdin);

    //freopen("out.txt","w",stdout);

    std::ios::sync_with_stdio(false);

    init();

    string s1,s2;

    cin>>n>>s1>>s2;

    s[0]=stoi(s1.substr(0,4)),s[1]=stoi(s1.substr(4,2)),s[2]=stoi(s1.substr(6,2)),s[3]=stoi(s1.substr(8,2)),s[4]=stoi(s1.substr(10,2));;

    t[0]=stoi(s2.substr(0,4)),t[1]=stoi(s2.substr(4,2)),t[2]=stoi(s2.substr(6,2)),t[3]=stoi(s2.substr(8,2)),t[4]=stoi(s2.substr(10,2));;

    string str;

    getline(cin,str);

    for(int i=1;i<=n;i++){

        getline(cin,str);

        solve(i,str);

    }

    func();

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值