[AOJ] No. 0261 マヤの大予言

2020年12月15日

問題

方針

時刻の変換と同じように、いったん最小単位に変換してから計算を行います。西暦からマヤ歴への変換は、2012年12月21日からどれだけの日数が経過したかどうかを計算します。このときうるう日に気を付けます。マヤ歴から西暦への変換は、西暦の年数を二分探索によって求めます。

コード

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

ll mod = 1872000;
ll day[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

ll todays(ll y, ll m, ll d) {
    ll ret = (y - 1) * 365 + (y - 1) / 4 - (y - 1) / 100 + (y - 1) / 400 + d;
    if ((y % 4 == 0 && y % 100 != 0) ||( y % 400 == 0)) {
        if (m > 2) ret++;
    }
    for (int i = 0; i < m - 1; i++) {
        ret += day[i];
    }
    return ret;
}

void stom(ll y, ll m, ll d) {
    ll a[5]{};
    a[4] = 1;
    a[3] = 20;
    a[2] = a[3] * 18;
    a[1] = a[2] * 20;
    a[0] = a[1] * 20;
    
    ll t = todays(y, m, d) - todays(2012, 12, 21);
    t %= mod;
    ll c[5]{};
    c[0] = t / a[0];
    c[1] = (t - c[0] * a[0]) / a[1];
    c[2] = (t - c[0] * a[0] - c[1] * a[1]) / a[2];
    c[3] = (t - c[0] * a[0] - c[1] * a[1] - c[2] * a[2]) / a[3];
    c[4] = t - c[0] * a[0] - c[1] * a[1] - c[2] * a[2] - c[3] * a[3];
    for (int i = 0; i < 5; i++) {
        if (i == 4) {
            cout << c[i] << "\n";
        } else {
            cout << c[i] << ".";
        }
    }
}

void mtos(ll b, ll ka, ll t, ll w, ll ki) {
    ll f = b * 20 * 20 * 18 * 20;
    f += ka * 20 * 18 * 20;
    f += t * 20 * 18;
    f += w * 20 + ki;
    f += todays(2012, 12, 21);
    
    ll l = -1;
    ll r = 100000000;
    while (r - l > 1) {
        ll m = (l + r) / 2;
        if (todays(m, 1, 1) <= f) {
            l = m;
        } else {
            r = m;
        }
    }
    
    ll y = l;
    ll m = 1;

    f -= todays(y - 1, 12, 31);
    for (int i = 0; i < 12; i++) {
        int g = day[i];
        if (y % 4 == 0 && y % 100 != 0 || y % 400 == 0) {
            if (i == 1) g = 29;
        }
        if (f - g <= 0) {
            m = i + 1;
            break;
        } else {
            f -= g;
        }
    }
    cout << y << "." << m << "." << f << "\n";
}

int main() {
    string s;
    cin >> s;
    while (s != "#") {
        vector<ll> v;
        string t = "";
        for (int i = 0; i < s.length(); i++) {
            if (s[i] == '.') {
                v.push_back(stoi(t));
                t = "";
            } else if (i == s.length() - 1) {
                t += s[i];
                v.push_back(stoi(t));
            } else {
                t += s[i];
            }
        }
        if (v.size() == 3) {
            stom(v[0], v[1], v[2]);
        } else {
            mtos(v[0], v[1], v[2], v[3], v[4]);
        }
        cin >> s;
    }
    return 0;
}