CCF 节日 满分代码 + 解题思路 (两种解法 :公式法 和 模拟法) + 技巧总结 201503-3

题目描述

在这里插入图片描述


解题思路1 :公式法

  • 该题数据范围不大,只有两百年,可以采用暴力枚举来解题
  • 计算日期的公式,当你知道某一天是星期几,再根据其他日子与该天的相差天数,就可以推算出其他日子星期几,总结规律可知: (星期几 + 相差的天数) % 7 = 改天的星期几 (这里的星期几用0,1,2,3,4,5,6表示,因为取余的是7
  • 对于不需要计算的年份以及月份,只需要累计一年或一个月的天数即可
  • 只需要对需要计算的年数的对应月,首先计算出这个月的第一天是星期几,再遍历这个月的每一天,并累计星期c出现的次数,当这个月遍历完后,判断是否有第b个星期c,有则输出,没有则输出none

解题思路2 :暴力枚举

  • 该题数据范围不大,只有两百年,可以采用暴力枚举来解题
  • 创建一个时间结构体,记录每一天对应的时间参数(年、月、日、星期1~7出现的次数、星期x)
  • 并在结构体数组内创建加一天的函数,判断是否为闰年的函数、获取每个月有多少天的函数、判断该天是不是最后一天的函数等等
  • 只需要从1850年1月1日,无脑加一天遍历,并将每天的日期与期望的a月第b个星期c与该天的参数进行比对,如果参数一致,则将日期输出
  • 设置一个输出标志,如果这一年需要输出结果并且已经输出则标志位true,反之标志为false,并且在该年的最后一天仍未找到答案,则输出none

技巧总结

  • 计算日期一般就是用到代码中的那三个函数,灵活加以应用
  • 如果数据范围不是很大,就暴力枚举天数,思路比较清晰
  • 计算星期的公式 : (已知星期几 + 相差天数 ) % 7 = 所求星期几
  • printf(“%04d/%02d/%02d\n”, year, month, d) //占位输出日期的简便写法

代码实现1

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

int a, b, c, y1, y2;

int months[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

bool is_leap(int y)
{
    if (y % 400 == 0 || (y % 4 == 0 && y % 100)) return 1;
    return 0;
}

int getdays(int y, int m) //求每个月份的天数
{
    if (m == 2) return months[2] + is_leap(y);
    return months[m];
}

int main()
{
    cin >> a >> b >> c >> y1 >> y2;

    int days = 0;
    for (int year = 1850; year <= y2; year ++) //从1850/01/01开始枚举天数
    {
        if (year < y1) //如果<y1说明不需要输出结果,直接累加天数即可
        {
            days += (365 + is_leap(year));
            continue;
        }
        else
        {
        	//遍历每一年,对所求的月份单独处理,其余月份之后需要累加天数即可
            for (int month = 1; month <= 12; month ++)
            {
                if (month == a)
                {
                    int w = (days + 1) % 7; //每个月的第一天是星期几(注:w = [0,1,2,3,4,5,6]
                    int cnt = 0; //计数当前是第几个星期c
                    for (int d = 1; d <= getdays(year, month); d ++)
                    {
                        if (w == c - 1) //因为w移了一位,星期一时w = 0
                        {
                            cnt ++;
                            if (cnt == b) //当前是第b个星期c,输出结果
                            {
                                printf("%04d/%02d/%02d\n", year, month, d);
                            }
                        }
                        w = (w + 1) % 7; //更新w,取值范围为0~6
                    }
                    if (cnt < b) puts("none"); //该月不存在b个星期c
                }
                days += getdays(year, month);
            }
        }
    }
    return 0;
}


代码实现2

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

int M[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

struct time
{
    int year;
    int month;
    int day;
    int week[8]; //这个变量不能是一个整型记录周数,这个变量需要记录每个星期x在这个月出现了几次
    int weekday;

    bool is_leap() //返回是否是闰年
    {
        return (year % 400 == 0 || (year % 4 == 0 && year % 100));
    }

    int get_day() //返回某年某月有多少天
    {
        if (month == 2) return M[month] + is_leap();
        return M[month];
    }

    void add()
    {
        day ++;
        weekday ++;
        if (weekday > 7) weekday = 1;
        week[weekday] ++;
        if (day > get_day())
        {
            day = 1; //新的一个月,天数和记录星期x出现的周数数组都要初始化
            memset(week, 0, sizeof(week));
            week[weekday] ++;

            month ++;
            if (month > 12)
            {
                month = 1;
                year ++;
            }
        }
    }

    bool is_last() //返回这天是不是今天的最后一天
    {
        return month == 12 && day == get_day();
    }

    int wnum() //返回今天星期x在这个月出现的次数
    {
        return week[weekday];
    }
};

int a, b, c, y1, y2;

bool check(time t) //判断是否是a月的b个星期c
{
    return ((t.month == a) && (t.wnum() == b) && (t.weekday == c));
}

int main()
{
    cin >> a >> b >> c >> y1 >> y2;
    time cur = {1850, 1, 1, {0, 0, 1, 0 , 0, 0, 0, 0}, 2}; //起始日期初始化,其中week[2] = 1,表示出现过一次星期二

    bool cf = false; //输出标记
    while (cur.year <= y2)
    {
        if (cur.year >= y1 && check(cur))
        {
            cf = true; //输出过
            cout << cur.year << "/";//输出年

            //输出月
            if (cur.month < 10) cout << 0 << cur.month << "/";
            else cout << cur.month << "/";

            //输出日
            if (cur.day < 10) cout << 0 << cur.day << endl;
            else cout << cur.day << endl;
        }

        if (cur.year >= y1 && cur.is_last()) //这一年需要输出答案并且今天是今年的最后一天
        {
            if (cf) cf = false; //如果今年的答案已经输出,那么重置输出标志
            else puts("none"); //如果今年没有合适的答案,则输出none
        }
        //cout << cur.month << " " << cur.day << " " << cur.wnum() << " " << cur.weekday << endl;
        //当时40分,就是卡在week出了问题,通过上一行的输出就可以发现问题,输出debug yyds!!
        cur.add(); //天数加一,模拟日期进位
    }
    return 0;
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只可爱的小猴子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值