前言
在刚做这道题时,我根本不知道蔡勒公式是什么,只是想自己总结一下规律,就问了Deepseek几个日期是星期几——结果他直接用蔡勒公式秒了.
我大为惊奇,就查了下资料,向大家介绍这个公式,以及这道题的蔡勒公式做法,希望对大家有帮助。
正文
蔡勒公式(Zeller's Congruence)是一种快速计算给定日期是星期几的数学公式,由德国数学家克里斯蒂安·蔡勒(Christian Zeller)于1883年提出。它适用于格里高利历(公历),能高效处理历史或未来日期的星期计算。
一、公式的两种形式
蔡勒公式有两种版本,分别对应 月份的不同处理方式:
简化版(月份从3月开始计数)
-
将1月和2月视为上一年的13月和14月。(重点!)
-
例如:1900年1月 → 视为1899年13月;1900年2月 → 视为1899年14月
-
公式:
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: 星期几(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 |
二、公示证明
(这里给出的是简化版证明)
一、基准日与目标日期的天数差
-
选择基准日:
通常选择某年的3月1日作为基准(因为1月和2月被视为上一年的13月和14月,简化了闰年计算)。 -
目标日期:
设目标日期为 q年m月d日(若m=1或2,则视为m+12月,年份减1)。 -
计算总天数差:
总天数差 = 年份贡献 + 月份贡献 + 日期贡献。
二、分解各部分的贡献
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;
}
后记
(求点赞,关注)