USACO-Chapter1-Section 1.1-Friday the Thirteenth (friday)
【题目描述】
13号又是一个星期五。13号在星期五比在其他日子少吗?为了回答这个问题,写一个程序,要求计算每个月的十三号落在周一到周日的次数。给出N年的一个周期,要求计算1900年1月1日至1900+N-1年12月31日中十三号落在周一到周日的次数,N为正整数且不大于400.
这里有一些你要知道的:
1、1900年1月1日是星期一.
2、4,6,11和9月有30天.其他月份除了2月都有31天.闰年2月有29天,平年2月有28天.
3、年份可以被4整除的为闰年(1992=4*498 所以 1992年是闰年,但是1990年不是闰年).
4、以上规则不适合于世纪年。可以被400整除的世纪年为闰年,否则为平年。所以,1700,1800,1900和2100年是平年,而2000年是闰年.
【输入格式】
一个正整数n.
【输出格式】
七个在一行且相分开的整数,它们代表13日是星期六,星期日,星期一...星期五的次数.
【输入样例】
20
【输出样例】
36 33 34 33 35 35 34
【思路】
一(模拟法)
按月为单位,模拟,1900年1月13日是星期六,那么下一个13日的星期就是(b[i]+13) mod 7,b[i]∈(31,28(29),31,30,……)。这里数据较弱,可以AC,但是当数据BT了,怎么办?这里推荐个按照年计算的方法。当数据比较大时,可以以年为单位计算,每年为365天,mod 7的余数是1,就是说每过一年所有的日和星期错一天,闰年第1、2月错1天,3月以后错2天。这样,只要先求出第一年的解,错位添加到以后的年即可。
二(公式法)
看到NOCOW上有神牛贴出来蔡勒公式,MS是个计算星期几的公式,很牛X。我把它贴出来大家看下。
- 蔡勒公式是一种计算任何一日属一星期中哪一日的算法,由蔡勒(Julius Christian Johannes Zeller)推算出。

公式都是基于公历的置闰规则来考虑。
公式中的符号含义如下: - w:星期
- c:世纪(前两位数)
- y:年(后两位数)
- m:月(m 的取值范围为 3 至 14,即在蔡勒公式中,某年的 1、2月要看作上一年的 13、14月来计算,比如2003年1月1日要看作2002年的13月1日来计算)
- d:日
- [ ]:称作高斯符号,代表取整,即只要整数部份。
- mod:同余(这里代表括号里的答案除以 7 后的余数)(请注意前面是负数取模的情况,取模只可以是正数)若要计算的日期是在1582年10月4日或之前,公式则为
(因罗马教皇修改历法,把1582年10月4日的下一天改为1582年10月15日)
※。3200不是闰年,详见WIKI。
【代码】
一、模拟法
- Executing...
- Test 1: TEST OK [0.000 secs, 276 KB]
- Test 2: TEST OK [0.000 secs, 276 KB]
- Test 3: TEST OK [0.000 secs, 276 KB]
- Test 4: TEST OK [0.000 secs, 276 KB]
- Test 5: TEST OK [0.000 secs, 276 KB]
- Test 6: TEST OK [0.000 secs, 276 KB]
- Test 7: TEST OK [0.000 secs, 276 KB]
- Test 8: TEST OK [0.000 secs, 276 KB]
- All tests OK.
{
ID : c_CaM.19
LANG: PASCAL
TASK: friday
}
Program CaM(input,output);
Var
i,j,t,n:longint;
a,b:array[0..13] of longint;
Procedure innt;
Begin
assign(input,'friday.in'); reset(input);
assign(output,'friday.out'); rewrite(output);
End;
Procedure outt;
Begin
close(input);
close(output);
End;
Begin
innt;
a[1]:=31; a[3]:=31; a[5]:=31; a[7]:=31;
a[8]:=31; a[10]:=31; a[12]:=31;
a[4]:=30; a[6]:=30; a[9]:=30; a[11]:=30;
readln(n); t:=0;
for i:=1900 to 1900+n-1 do
Begin
if (i mod 400=0)or((i mod 4=0)and(i mod 100<>0)) then a[2]:=29
else a[2]:=28;
for j:=1 to 12 do
Begin
inc(b[(t+13)mod 7]);
inc(t,a[j]);
End;
End;
writeln(b[6],' ',b[0],' ',b[1],' ',b[2],' ',b[3],' ',b[4],' ',b[5]);
outt;
End.
二、公式法(非笔者)
{根据蔡勒公式写的代码。
ID: Boolean93
PROG: friday
LANG: PASCAL
}
var
n,i,j,year,m,c,y,w :longint;
a :array[0..6] of longint;
begin
Assign(input,'Friday.in');reset(input);
Assign(output,'Friday.out');rewrite(output);
readln(n);
for i:=1900 to 1899+n do
for j:=1 to 12 do
begin
year:=i;
m:=j;
if (m=1)or(m=2) then
begin
dec(year);
m:=m+12;
end;
c:=year div 100;
y:=year mod 100;
w:=(y+ y div 4 + c div 4 -2*c+ 26*(m+1) div 10 +13 -1) mod 7;
w:=(w+7) mod 7;
inc(a[w]);
end;
writeln(a[6],' ',a[0],' ',a[1],' ',a[2],' ',a[3],' ',a[4],' ',a[5]);
Close(input);close(output);
halt;
end.
浙公网安备 33010602011771号