对于一个日期,我们可以计算出年份的各个数位上的数字之和,也可以分别计算月和日的各位数字之和

此题为第十五届蓝桥杯模拟赛(第一期)Python赛道的第三题 填空题

问题描述

对于一个日期,我们可以计算出年份的各个数位上的数字之和,也可以分别计算月和日的各位数字之和。请问从 1900 年 1 月 1 日至 9999 年 12 月 31 日,总共有多少天,年份的数位数字之和等于月的数位数字之和加日的数位数字之和。
例如,2022年11月13日满足要求,因为 2+0+2+2=(1+1)+(1+3) 。
请提交满足条件的日期的总数量。

答案提交

这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

我的解题

分析

需要遍历年份 1900~9999 、月份及所对应的天数,这里就需要考虑一个平闰年的区分了,主要体现在 2 月上,其它都好说:

  1. 我们需要遍历 1900 年到 9999 年,以及所对应的月份及其所对应的天数。所以我们可以先判断输入的月份是否为大小月,大月输出 31 天,小月输出 30 天,但是 2 月可能会因为平闰年使得天数存在 28 天、29 天的情况。
  2. 第一个函数我们可以先写出传入年、月的,除了 2 月以外的月份我们就直接输出其天数(根据大小月),对于 2 月,我们需要根据输入的年份判断是否是平闰年输出 29、28 天。所以第二个函数我们写判断闰年的,输入为年份,是闰年输出 29 天、不是闰年输出 28 天。
  3. 完成以上两个主要函数后,最后就是对年份、月份、日的位数分别求和,所以写第三个函数用于传入数值,对此数值的各个位求和输出结果就行了。
  4. 在主干代码中就是遍历年份、月份、日了,然后判断年份数位之和是否与月日的数位之和相等,相等就引入一个变量去累计,最后遍历完成输出就行了。

编程

以下是本人实践的代码:

#判断平闰年并输出对应2月的天数
def leapYear(year):
    if year%4==0 and year%100!=0 or year%400==0:
        return 29
    else:
        return 28
#输出对应大小月所对应的天数
def monthDays(year,month):
    if month in [1,3,5,7,8,10,12]:
        return 31
    elif month in [4,6,9,11]:
        return 30
    elif month==2:
        return leapYear(year)
#数字的数位求和
def sumDigits(num):
    sum=0
    while num!=0:
        sum += num % 10
        num = num // 10
    return sum
if __name__ == '__main__':
    count = 0
    for num_year in range(1900,10000):  #遍历年
        for num_month in range(1,13): #遍历月
            for num_day in range(1,monthDays(num_year,num_month)+1): #遍历月份所对应的日
                if sumDigits(num_year) == sumDigits(num_month) + sumDigits(num_day):
                    count += 1
    print(count)

运行结果

运行结果

结果是 70910

AI 解题

问了几个大模型(通义千问的 qwen-max、qwen-plus、qwen-turbo,智谱 AI 的 ChatGLM-Turbo,讯飞星火 V3.0),都存在问题,要么运行出错,要么一些小细节没有考虑进去,导致结果有所偏差,下面我给出来他们的代码并 AI 注释,但是有些地方还是值得学习的。

qwen-max

原始代码

from datetime import datetime, timedelta

def digit_sum(n):
    return sum(int(digit) for digit in str(n))

count = 0
start_date = datetime(1900, 1, 1)
end_date = datetime(9999, 12, 31)

for year in range(start_date.year, end_date.year + 1):
    for month in range(1, 13):
        for day in range(1, (datetime(year, month, 1).replace(day=1) + timedelta(days=32)).day):
            if digit_sum(year) == digit_sum(month) + digit_sum(day):
                count += 1

print(count)

代码存在问题,OverflowError: date value out of range

不修复了,懒……

不过其取月份所对应的天数倒是有点意思,datetime()函数也不错,记下来了。

讯飞星火 V3.0

原始代码

def is_valid_date(year, month, day):
    # 判断日期是否有效
    if year < 1900 or year > 9999:
        return False
    if month < 1 or month > 12:
        return False
    if day < 1 or day > 31:
        return False
    return True

def sum_of_digits(n):
    # 计算数字的各个位数的和
    return sum(map(int, str(n)))

def count_valid_dates():
    count = 0
    for year in range(1900, 10000):
        for month in range(1, 13):
            for day in range(1, 32):
                if is_valid_date(year, month, day):
                    if sum_of_digits(year) == sum_of_digits(month) + sum_of_digits(day):
                        count += 1
    return count

result = count_valid_dates()
print(result)

代码中有一个地方存在问题,就是遍历的当前月份天数(第 19 行),它并没有将大小月、平闰年考虑进去,故运行后的得到的结果 71834 不准确;再者,其代码中对年月日的效验有些多余,没有实际效果,所以我对其修改后就可以得到正确的答案了:

修复后的代码

#判断平闰年并输出对应2月的天数
def leapYear(year):
    if year%4==0 and year%100!=0 or year%400==0:
        return 29
    else:
        return 28
#输出对应大小月所对应的天数
def monthDays(year,month):
    if month in [1,3,5,7,8,10,12]:
        return 31
    elif month in [4,6,9,11]:
        return 30
    elif month==2:
        return leapYear(year)
def sum_of_digits(n):
    # 计算数字的各个位数的和
    return sum(map(int, str(n)))

def count_valid_dates():
    count = 0
    for year in range(1900, 10000):
        for month in range(1, 13):
            for day in range(1, monthDays(year,month)+1):
                if sum_of_digits(year) == sum_of_digits(month) + sum_of_digits(day):
                    count += 1
    return count

result = count_valid_dates()
print(result)

运行结果是 70910。

评价:该大模型对各个数位求和非常的巧妙,用了高阶函数 map()和 sum()函数进行求和,牛!

qwen-plus

原始代码

def digit_sum(n):
    """
    计算一个数的数字和
    参数:
        n:整数
    返回值:
        数字和
    """
    return sum(int(digit) for digit in str(abs(n)))

count = 0
for year in range(1900, 10000):
    for month in range(1, 13):
        for day in range(1, (month == 2 and (year % 4 == 0 and (year % 100 != 0 or year % 400 == 0) or year % 4 != 0) + 29) or 31):
            """
            考虑闰年和平年的天数
            """
            if digit_sum(year) == digit_sum(month) + digit_sum(day):
                count += 1

print(count)

运行结果是 70388。

相比之下,结果漏了好多,现在对其分析分析:可以发现第 7 行代码貌似少了 30、28 这两个选项,就是小月的天数和平年的 2 月的天数。

不过其对数位求和方式也很独特,利用 sum()函数和推导式求和。

此处暂时不修复代码了,麻烦。

qwen-turbo

原始代码

def count_days():
    """
    计算满足年份、月份和日期之和相等的天数
    """
    total_days = 0
    for year in range(1900, 10000):
        if len(str(year)) == 4:
            for month in range(1, 13):
                if len(str(month)) == 1 or len(str(month)) == 2:
                    for day in range(1, 32):
                        if len(str(day)) == 1 or len(str(day)) == 2:
                            year_sum = sum(int(digit) for digit in str(year))
                            month_sum = sum(int(digit) for digit in str(month))
                            day_sum = sum(int(digit) for digit in str(day))
                            if year_sum == month_sum + day_sum:
                                total_days += 1
    return total_days

print(count_days())

运行结果是 71834。

结果明显大了,查看代码,发现第 10 行的天数没有去考虑大小月,闰平年的二月天数,所以其结果是偏大的。

此处不修复代码了,其数位求和也是用的推导式和 sum()函数组合。


存档地址:https://www.yuque.com/worthstudy/study/mphfsxuhm900647s

© 版权声明
THE END
喜欢就点赞支持一下吧,如果觉得不错或日后有所需要,可以收藏文章和关注作者哦。
点赞1打赏 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容