前言

在刚做这道题时,我根本不知道蔡勒公式是什么,只是想自己总结一下规律,就问了Deepseek几个日期是星期几——结果他直接用蔡勒公式秒了.

我大为惊奇,就查了下资料,向大家介绍这个公式,以及这道题的蔡勒公式做法,希望对大家有帮助。

题目传送门

正文

蔡勒公式(Zeller's Congruence)是一种快速计算给定日期是星期几的数学公式,由德国数学家克里斯蒂安·蔡勒(Christian Zeller)于1883年提出。它适用于格里高利历(公历),能高效处理历史或未来日期的星期计算。


一、公式的两种形式

蔡勒公式有两种版本,分别对应 月份的不同处理方式:

简化版(月份从3月开始计数)

  • 将1月和2月视为上一年的13月和14月。(重点!)

  • 例如:1900年1月 → 视为1899年13月;1900年2月 → 视为1899年14月

  • 公式

h = \left( q + \left\lfloor \frac{13(m+1)}{5} \right\rfloor + K + \left\lfloor \frac{K}{4} \right\rfloor + \left\lfloor \frac{J}{4} \right\rfloor + 5J \right) \mod 7

h: 星期几(0=星期六, 1=星期日, 2=星期一, ..., 6=星期五

q: 日期(1-31)

m: 月份(3-14,对应1月到12月)

K: 年份的后两位(如1899年→K=99)

J: 年份的前两位(如1899年→J=18)


扩展版(月份从1月开始计数)

扩展版的蔡勒公式(Zeller's Congruence)直接使用原始年份和月份,公式如下:

h = \left( q + \left\lfloor \frac{13(m + 3)}{5} \right\rfloor + K + \left\lfloor \frac{K}{4} \right\rfloor + \left\lfloor \frac{J}{4} \right\rfloor + 5J \right) \mod 7

h: 星期几(0=星期日, 1=星期一, 2=星期二, ..., 6=星期六,注意与简化版映射不同!

q: 日期(1-31)

m: 月份(1-12,无需调整,1月=1,2月=2)

J: 年份的前两位(如2023年→J=20)

K: 年份的后两位(如2023年→K=23)

扩展版与简化版的对比

特性 简化版 扩展版
月份处理 1月和2月需调整为13和14月 直接使用1-12月,无需调整
结果映射 0=星期六, 1=星期日, ..., 6=星期五 0=星期日, 1=星期一, ..., 6=星期六
公式项差异 使用 13(m+1)/5 使用 13(m+3)/5

、公示证明

(这里给出的是简化版证明)

一、基准日与目标日期的天数差

  1. 选择基准日
    通常选择某年的3月1日作为基准(因为1月和2月被视为上一年的13月和14月,简化了闰年计算)。

  2. 目标日期
    设目标日期为 q年m月d日(若m=1或2,则视为m+12月,年份减1)。

  3. 计算总天数差
    总天数差 = 年份贡献 + 月份贡献 + 日期贡献。


二、分解各部分的贡献

1. 年份贡献
  • 平年贡献:每平年贡献365天,即365mod  7=1365mod7=1天。

  • 闰年贡献:每闰年多1天(2月29日),即额外贡献1天。

  • 总年份贡献

    年份天数=(年份差×365+闰年数)mod  7年份天数=(年份差×365+闰年数)mod7

    其中,闰年数由公式中的 ⌊K/4⌋+⌊J/4⌋体现。

2. 月份贡献
  • 各月的天数差异通过 月份修正项 ⌊13(m+1)/5⌋近似。

  • 推导逻辑
    假设每月平均约30.6天,通过调整系数抵消月份天数的波动。例如:

    • 3月(m=3):修正项为 ⌊13×4/5⌋=10,对应3月贡献0天(基准月)。

    • 4月(m=4):修正项为 ⌊13×5/5⌋=13,对应4月贡献3天(31天)。

    • 依次类推,修正项将月份差异转化为整数偏移。

3. 日期贡献
  • 直接使用日期 q,即 d 天。


三、整合公式

将年份、月份和日期的贡献相加,并取模7:

代码展示

(仅供学习用)

#include<bits/stdc++.h>
using namespace std;
int ll[10];
//蔡勒公式
int zeller(int q, int m, int J, int K) {
    if (m == 1 || m == 2) {
        m += 12;
        int year = J * 100 + K - 1;  
        J = year / 100;              
        K = year % 100;              
    }
    int h = (q + 13*(m+1)/5 + K + K/4 + J/4 + 5*J) % 7;
    h%=7;
    return h;
}
int main(){
	int n;
	cin>>n;
	int y=1900;
	while(1900+n-1>=y){
		for(int i=1;i<=12;i++){
			ll[zeller(13,i,y/100,y%100)]++;
		}
		y++;
	}
	for(int i=0;i<=6;i++){
		cout<<ll[i]<<" ";
	}
	return 0;
}

后记

(求点赞,关注)

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐