1 条题解
-
0
解题思路
这道题目是关于玛雅历法系统的转换问题,需要将给定的玛雅历法循环日期(Calendar Round date)转换为对应的长纪历日期(Long Count date)。具体来说,题目要求我们:
-
验证输入的合法性:
- 检查卓尔金历(Tzolkin)的日数是否在1到13之间,且日名是否在给定的20个日名列表中。
- 检查哈布历(Haab)的日数是否合法:对于前18个月,日数应在1到20之间;对于第19个月(Wayeb),日数应在1到5之间。
-
计算历法循环日期的周期:
- 卓尔金历的周期是260天(13 × 20)。
- 哈布历的周期是365天(19个月 × 20天 - 5天)。
- 历法循环的周期是两者的最小公倍数,即18980天(260 × 73 = 365 × 52)。
-
长纪历日期的计算:
- 已知长纪历日期8.0.0.0.0对应历法循环日期9 Ajaw 3 Sip。
- 我们需要找到所有在伯克盾8和9(即长纪历天数在1152000到1872000之间)的日期,使得其对应的历法循环日期与输入匹配。
-
使用中国剩余定理(CRT)求解:
- 将问题转化为求解两个同余方程:
- 总天数 ≡ a (mod 260)
- 总天数 ≡ b (mod 365)
- 使用CRT找到满足条件的最小解,并在伯克盾8和9的范围内枚举所有可能的解。
- 将问题转化为求解两个同余方程:
-
输出结果:
- 将所有合法的长纪历日期按升序排序后输出。
#include <iostream> #include <vector> #include <string> #include <unordered_map> #include <algorithm> using namespace std; using int64 = long long; // 安全取模 int64 mod(int64 a, int64 m) { int64 r = a % m; return r < 0 ? r + m : r; } int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); // Tzolkin 名称及索引 vector<string> tzNames = { "Imix","Ik","Akbal","Kan","Chikchan","Kimi","Manik","Lamat","Muluk","Ok", "Chuen","Eb","Ben","Ix","Men","Kib","Kaban","Etznab","Kawak","Ajaw" }; unordered_map<string,int> tzIndex; for(int i=0;i<20;i++) tzIndex[tzNames[i]] = i; // Haab 月份名称及索引 vector<string> haabNames = { "Pohp","Wo","Sip","Zotz","Sek","Xul","Yaxkin","Mol","Chen","Yax", "Sak","Keh","Mak","Kankin","Muan","Pax","Kayab","Kumku","Wayeb" }; unordered_map<string,int> haabIndex; for(int i=0;i<19;i++) haabIndex[haabNames[i]] = i; vector<int> haabLen(19,20); haabLen[18] = 5; // Wayeb // 长计数单位 const int64 DAY_PER_WINAL = 20; const int64 DAY_PER_TUN = 18 * DAY_PER_WINAL; // 360 const int64 DAY_PER_KATUN = 20 * DAY_PER_TUN; // 7200 const int64 DAY_PER_BAKTUN = 20 * DAY_PER_KATUN; // 144000 // 参考:8.0.0.0.0 对应总天数 const int64 totalDaysRef = 8 * DAY_PER_BAKTUN; // 1152000 // 参考 CR = 9 Ajaw 3 Sip → offsetRefCR=99、dayInHaabRef=42 const int64 offsetRefCR = 99; const int64 dayInHaabRef = 2*20 + 2; // 3 Sip → 月索引2,日号3→2 // 预计算用于 CR → totalDays 的常数 Kt, Kh const int64 Kt = mod(offsetRefCR - totalDaysRef, 260LL); const int64 Kh = mod(dayInHaabRef - totalDaysRef, 365LL); int d; cin >> d; while(d--){ int tzNum, haabNum; string tzName, haabMon; cin >> tzNum >> tzName >> haabNum >> haabMon; // 验证 Haab 合法性 bool legal = true; if(!haabIndex.count(haabMon)) legal = false; int mIdx = legal ? haabIndex[haabMon] : -1; if(legal){ if(haabNum < 1 || haabNum > haabLen[mIdx]) legal = false; } if(!legal){ cout << "0\n"; continue; } int64 targetHaab = (int64)mIdx * 20 + (haabNum - 1); // 验证 Tzolkin 合法性 if(!tzIndex.count(tzName) || tzNum < 1 || tzNum > 13){ cout << "0\n"; continue; } int ai = tzNum - 1, bi = tzIndex[tzName]; // CRT 求 Tzolkin offsetInput mod260 int offsetInput = -1; for(int m=0;m<13;m++){ int x = bi + 20*m; if(x % 13 == ai){ offsetInput = x; break; } } if(offsetInput < 0){ cout << "0\n"; continue; } // 两个同余: totalDays ≡ a (mod260),≡ b (mod365) int64 a = mod(offsetInput - Kt, 260LL); int64 b = mod(targetHaab - Kh, 365LL); // 可解性检查:gcd(260,365)=5 if((a - b) % 5 != 0){ cout << "0\n"; continue; } // 枚举找到最小解 x0 mod lcm=18980 const int64 lcm = 18980; int64 x0 = -1; for(int k=0;k<365/5;k++){ int64 x = a + 260LL * k; if(x % 365 == b){ x0 = mod(x, lcm); break; } } if(x0 < 0){ cout << "0\n"; continue; } // 在 baktun 8..9 范围内枚举 int64 start = totalDaysRef; int64 end = 10 * DAY_PER_BAKTUN - 1; int64 nlo = (start - x0 + lcm - 1) / lcm; int64 nhi = (end - x0) / lcm; vector<array<int,5>> results; for(int64 n=nlo; n<=nhi; n++){ int64 TD = x0 + n*lcm; if(TD < start || TD > end) continue; // 解码为 B.K.T.W.I int64 t = TD; int B = t / DAY_PER_BAKTUN; t %= DAY_PER_BAKTUN; int K = t / DAY_PER_KATUN; t %= DAY_PER_KATUN; int T = t / DAY_PER_TUN; t %= DAY_PER_TUN; int W = t / DAY_PER_WINAL; t %= DAY_PER_WINAL; int I = t; if(B==8 || B==9){ results.push_back({B,K,T,W,I}); } } sort(results.begin(), results.end()); cout << results.size() << "\n"; for(auto &v : results){ cout << v[0] << "." << v[1] << "." << v[2] << "." << v[3] << "." << v[4] << "\n"; } } return 0; }
-
- 1
信息
- ID
- 432
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 5
- 已通过
- 0
- 上传者