问题描述
上周末, M.A 教授对古老的玛雅有了一个重大发现。从一个古老的节绳(玛雅人用于记事的工具)中,教授发现玛雅人使用了一个一年有 365 的叫做 Haab 的日历。这个Haab 日历拥有 19 个月,在开始的 18 个月,一个月有 20 天,月份的名字分别是 pop, no,zip, zotz, tzec, xul, yoxkin, mol, chen, yax, zac, ceh, mac, kankin, muan, pax, koyab, cumhu.这些月份中的日期用 0 到 19 表示。 Haab 历的最后一个月叫做 uayet,它只有 5 天,用 0 到 4 表示。玛雅人认为这个日期最少的月份是不吉利的,在这个月法庭不开庭,人们不从事交易,甚至没有人打扫屋中的走廊。
因为宗教的原因,玛雅人还使用了另一个日历,在这个日历中年被称为 Tzolkin(holly年),一年被分成 13 个不同的时期,每个时期有 20 天,每一天用一个数字和一个单词相组合的形式来表示。使用的数字是 1~13,使用的单词共有 20 个,它们分别是: imix,ik, akbal, kan, chicchan, cimi, manik, lamat, muluk, ok, chuen, eb, ben, ix, mem, cib, caban,eznab, canac, ahau。注意:年中的每一天都有着明确的描述,比如,在一年的开始,日期如下描述: 1 imix, 2 ik, 3 akbal, 4 kan, 5 chicchan, 6 cimi, 7 manik, 8 lamat, 9 muluk, 10 ok, 11 chuen, 12 eb, 13 ben, 1 ix, 2 mem, 3 cib, 4 caban, 5 eznab, 6 canac, 7 ahau, , 8 imix, 9 ik, 10 akbal . . . 。也就是说数字和单词各自独立循环使用。
Haab 历和 Tzolkin 历中的年都用数字 0, 1,:::表示,数字 0 表示世界的开始。所以第一天被表示成:
Haab: 0. pop 0
Tzolkin: 1 imix 0
请帮助 M.A.教授写一个程序可以把 Haab 历转化成 Tzolkin 历
输入数据
Haab 历中的数据由如下的方式表示:
日期. 月份 年数
第一行表示要转化的 Haab 历的数据量。下面的每一行表示一个日期,年数小于5000。
输出要求
Tzolkin 历中的数据由如下的方式表示:
天数字 天名称 年数
第一行表示需要转化的 Haab 历的数据量。下面的每一行表示一个日期。
输入样例
3
10. zac 0
0. pop 0
10. zac 1995
输出样例
3
3 chuen 0
1 imix 0
9 cimi 2801
解题思路
这道题问的是如何将 Haab 历的日期转换为 Tzolkin 历的日期。首先我们要搞清楚这两种日历记述日期的规则。 Haab 历每年 365 天,分成 19 个月,前 18 个月每月 20 天,第 19个月有 5 天, 19 个月的名字分别用不同的字符串表示。每个月的日期是从 0 开始顺序记录的。若要计算出某个月的某一天是当年的第几天,可以将相应的月份用 0~18 表示,然后通过公式:月份*20+日期+1 来计算。 Tzolkin 历一年有 260 天,每个日期由数字部分和字符串部分组合而成。日期部分从 1~13 循环使用,字符串部分由 20 个不同的字符串循环取出使用。可以看出, Tzolkin 历中的日期的两个组成部分是彼此独立的,对于一年中的某一天,可以分别求出其数字部分和字符串部分,然后将其简单组合起来。这里正好 260 是 13 和 20的最小共倍数,所以一年中没有两天是一样的,并且数字和字符串的所有组合都被用来表示一年的某一天了。接下来我们可以分析一下题目的具体解法。
总的思路是首先计算出给出的 Haab 历表示的日期是世界开始后的第几天(假设是 k),然后用 k 除以 260 得到 Tzolkin 历的年份,再用 k 对 260 取模得到 m,用 m 分别对 13 和 20取模得到 d 和 s, d 和 Tzolkin 历中第 s 个字符串的组合就是要求的日期。这里需要注意的是如果我们把世界的第 1 天用 0 表示,第 260 天用 259 表示,则正好用这个数字除以 260 得到Tzolkin 历的年份, m 对 13 取模后得到 0 到 12 的值,这个值要加 1 才能用于表示 Tzolkin历的日期,同时 m 对 20 取模后得到 0~19 的数值,分别表示取 20 个字符串中的一个。如果我们用字符串数组来存储这 20 个字符串,则 0~19的取值正好对应需要的字符串的数组下标。
参考程序
#include <iostream>
#include <cstdio>
using namespace std;
const int NAMELEN=10;
char month1[19][NAMELEN] = {"pop","no","zip","zotz","tzec","xul","yoxkin","mol","chen","yax","zac",
"ceh","mac","kankin","muan","pax","koyab","cumhu","uayet"};
char month2[20][NAMELEN] = {"imix","ik","akbal","kan","chicchan","cimi","manik","lamat","muluk",
"ok","chuen","eb","ben","ix","mem","cib","caban","eznab","canac","ahau"};
int main()
{
int nCases,i,m;
cin>>nCases;
cout<<nCases<<endl;
for(i=0;i<nCases;i++){
int day,year,dates;
char month[NAMELEN];
scanf("%d. %s %d",&day,month,&year);//读入 Haab 历的年月日
for(m=0;m < 19;m++){
if(!strcmp(month1[m],month))
break;
}
dates = year * 365 + m * 20 + day;//计算距离世界开始的天数,从 0 开始
printf("%d %s %d\n",1+dates%13,month2[dates%20],dates/260);//输出
}
return 0;
}