1 条题解

  • 0
    @ 2025-5-4 13:57:09

    解题思路

    这道题目是关于玛雅历法系统的转换问题,需要将给定的玛雅历法循环日期(Calendar Round date)转换为对应的长纪历日期(Long Count date)。具体来说,题目要求我们:

    1. 验证输入的合法性

      • 检查卓尔金历(Tzolkin)的日数是否在1到13之间,且日名是否在给定的20个日名列表中。
      • 检查哈布历(Haab)的日数是否合法:对于前18个月,日数应在1到20之间;对于第19个月(Wayeb),日数应在1到5之间。
    2. 计算历法循环日期的周期

      • 卓尔金历的周期是260天(13 × 20)。
      • 哈布历的周期是365天(19个月 × 20天 - 5天)。
      • 历法循环的周期是两者的最小公倍数,即18980天(260 × 73 = 365 × 52)。
    3. 长纪历日期的计算

      • 已知长纪历日期8.0.0.0.0对应历法循环日期9 Ajaw 3 Sip。
      • 我们需要找到所有在伯克盾8和9(即长纪历天数在1152000到1872000之间)的日期,使得其对应的历法循环日期与输入匹配。
    4. 使用中国剩余定理(CRT)求解

      • 将问题转化为求解两个同余方程:
        • 总天数 ≡ a (mod 260)
        • 总天数 ≡ b (mod 365)
      • 使用CRT找到满足条件的最小解,并在伯克盾8和9的范围内枚举所有可能的解。
    5. 输出结果

      • 将所有合法的长纪历日期按升序排序后输出。
    #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
    上传者