2018-12-3 ccf crontab 题解

这是ccf第三题中近年来博主见过的比较恶心的模拟题,涉及到模拟+文本处理,代码量较大。先看题目:
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
读完题目后,需要注意的几个地方:
1. 分钟、小时、天数、月数的取值范围
2. 分钟、小时前面可以有前导0
3. 大小写不区分
4. 时间的取值范围是左闭右开(博主当初没注意到,丢了30分,找了好几天才找到bug)
现在我们开始来寻找解题思路,很容易想到,从开始的时间到结束的时间,每一个时间都去寻找与之匹配的命令,符合则输出,但是这种很容易超时。所以采用另一种思路,找到每一项命令的执行时间,判断是否可以执行,这种思路比较清晰,也不会超时,可以做。下面看代码:

#include<bits/stdc++.h>
using namespace std;
long long star,end,syear,eyear;
set<long long> minu,hour,day,mon,we;
set<long long> temp; 
struct nd{              //woek为命令,num为时间 
    long long num;
    string work;
}endd[10000];
string Turn(string s)       //','转' '; 
{
    int len=s.length();
    for(int i=0;i<len;i++)
    {
        if(s[i]==',') s[i]=' ';
    }
    return s;
}
string Turnzm(string s)         //大写转小写 
{
    long long len=s.length(),i;
    for(i=0;i<len;i++)
    {
        if(s[i]>='A'&&s[i]<='Z') s[i]+=32;
    }
    return s;
}
long long Turn_int(string s)            //该函数可以把题目的所有格式转换为数字 
{
    s=Turnzm(s);
    if(s=="sun") return 0;
    if(s=="jan"||s=="mon") return 1;
    if(s=="feb"||s=="tue") return 2;
    if(s=="mar"||s=="wed") return 3;
    if(s=="apr"||s=="thu") return 4;
    if(s=="may"||s=="fri") return 5;
    if(s=="jun"||s=="sat") return 6;
    if(s=="jul") return 7;
    if(s=="aug") return 8;
    if(s=="sep") return 9;
    if(s=="oct") return 10;
    if(s=="nov") return 11;
    if(s=="dec") return 12;
    long long res;
    stringstream ss;
    ss<<s;
    ss>>res;
    return res;
}
void inputt(long long i, long long p)       //p代表该数据是分、小时、天、月或者周 
{
    if(p==1)                //1代表min 
        {
            minu.insert(i); 

        }
        if(p==2)                //2代表hour 
        {

            hour.insert(i); 

        }
        if(p==3)                //1代表day
        {
            day.insert(i); 
        }
        if(p==4)                //4 mon 
        {   
            mon.insert(i);  
        }
        if(p==5)
        {
            we.insert(i); 
        }
}
void Turntime(string s,long long p)     //得到每一时间部分的数据 
{
    long long i,j;
    if(s=="*")
    {
        if(p==1)                //1代表min 
        {
            for(long long i=0;i<60;i++)
            {
                inputt(i,p); 
            }
        }
        if(p==2)                //2代表hour 
        {
            for(long long i=0;i<24;i++)
            {
                inputt(i,p);
            }
        }
        if(p==3)                //3代表day
        {
            for(long long i=1;i<32;i++)
            {
                inputt(i,p);
            }
        }
        if(p==4)                //4 mon 
        {
            for(long long i=1;i<13;i++)
            {
                inputt(i,p);
            }
        }
        if(p==5)            //5代表周 
        {
            for(long long i=0;i<7;i++)
            {
                inputt(i,p);
            }
        }
        return ;
    }
    s=Turn(s);          //把','转化为' ' 
    stringstream ss(s);
    string st;
    while(ss>>st&&!st.empty())
    {
        long long ans=st.find('-'); 
        if(ans!=string::npos)
        {
            for(i=Turn_int(st.substr(0,ans));i<=Turn_int(st.substr(ans+1));i++ )        //-两边的数字 
            {
                inputt(i,p);
            }
        }
        else    inputt(Turn_int(st),p);
    }       
}
long long weekday(long long n)      //判断星期几 
{
    n=n/10000; 
    long long y=n/10000;n=n%10000;long long m=n/100;n=n%100;long long d=n;
    long long cday=0;
    long long monday[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
    for(long long i=1970;i<y;i++)
    {
        if((i%4==0&&i%100!=0)||i%400==0)
        cday+=366;
        else
        cday+=365;
    }
    if((y%4==0&&y%100!=0)||y%400==0) monday[2]=29;
    else monday[2]=28;
    for(long long i=1;i<m;i++)
    {
        cday+=monday[i];
    }
    cday=cday+d-1;
    cday=cday%7;
    if(cday==0) return 4;
    if(cday==1) return 5;
    if(cday==2) return 6;
    if(cday==3) return 0;
    if(cday==4) return 1;
    if(cday==5) return 2;
    if(cday==6) return 3;
}
bool pd_week(long long n)               //筛选判断星期 
{
    set<long long>::iterator p2;
    for(p2=we.begin();p2!=we.end();p2++)
        {
            if(weekday(n)==*p2)
            {
                return true;
            }
        }
        return false;
}
long long mon_day(long long m,long long y)  //该月含有的天数 
{
    if(m==2)
    {
        if((y%400)==0||(y%4==0&&y%100!=0))
        return 29;
        else
        return 28;
    }
    if(m==1||m==3||m==5||m==7||m==8||m==10||m==12)
    return 31;
    else 
    return 30;
}
bool pd(long long n)                //判断合法的日期和符合题目的时间 
{
    if(!pd_week(n)) return false;

    if(n<star||n>=end) return false;

    n=n/10000;
    long long y=n/10000;n=n%10000;long long m=n/100;n=n%100;long long d=n;
    if(mon_day(m,y)>=d) return true;
    return false;
}
bool cmp(nd a, nd b)        //排序函数 
{
    return a.num<b.num;
}
int  main()
{
    long long i,j,k=0,n;
    cin>>n>>star>>end;
    syear=star/100000000;
    eyear=end/100000000;

    cin.get(); 
    for(i=0;i<n;i++)
    {
        string s,st;
        minu.clear(); hour.clear(); day.clear(); mon.clear();we.clear();temp.clear();
        getline(cin,s);
        stringstream ss(s);
        for(j=1;j<=5;j++)                   //用流提取出五个部分,分别转化得到数字 
        {
            ss>>st;
            Turntime(st,j);         //得到组合 
        }
        set<long long>::iterator p1,p2,p3,p4;
        for(j=syear;j<=eyear;j++)
        {
            for(p4=mon.begin();p4!=mon.end();p4++)
            {
                for(p3=day.begin();p3!=day.end();p3++)
                {
                    for(p2=hour.begin();p2!=hour.end();p2++)
                    {
                        for(p1=minu.begin();p1!=minu.end();p1++)
                        {
                            long long res=j*100000000+(*p4)*1000000+(*p3)*10000+(*p2)*100+(*p1);
                            temp.insert(res); 
                        }
                    }
                }
            }
        }

        ss>>st;                                     //work

        for(p1=temp.begin();p1!=temp.end();p1++)    //判断,符合则存到数组中 
        {

            if(pd(*p1))
            {
                endd[k].work =st;
                endd[k++].num=*p1;
            }
        }   
    }
    stable_sort(endd,endd+k,cmp);       
    for(i=0;i<k;i++)
    cout<<endd[i].num <<' '<< endd[i].work<<endl;       //输出 
    return 0;
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值