メモ

自分に向けて書いたメモを取り扱っています.

AOJ 0261 Mayan Crucial Prediction

日本語なので省略

解説

  • マヤ暦→西暦

最大でも2016000日を処理するので愚直にループを回せばいける。
あと((((b*20+ka)*20+t)*18+w)*20+ki)とかで求めようとするとバグ埋め込む原因になった(自分の場合は)

  • 西暦→マヤ暦

先に閏年を求めるのでy-2013回ループを回すことになるが、その後は年月日を日数に変換するのにO(1)だしだいたい後の処理も定数がついたO(1)なので大丈夫。
ただオーバーフローに気をつけないと自分みたいにかなり時間を取られる…(糞雑魚)

コード

char s[16];
int month[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

bool leapYear(int y) {
    return (!(y % 4) && (y % 100)) || !(y % 400);
}

char ret[32];

string MayanToAD(void) {
    long long b, ka, t, w, ki, y, m, d;

    sscanf(s, "%lld.%lld.%lld.%lld.%lld", &b, &ka, &t, &w, &ki);

    long long dki = b * 144000 + ka * 7200 + t * 360 + w * 20 + ki;
    if(dki <= 10) y = 2012, m = 12, d = 21 + dki;
    else {
        dki -= 10;
        for(int yy = 2013; ; yy++) {
            for(int mm = 1; mm <= 12; mm++) {
                int tmp = (leapYear(yy) && mm == 2);
                for(int dd = 1; dd <= (month[mm] + tmp); dd++) {
                    dki--;
                    if(dki == 0) {
                        y = yy; m = mm; d = dd;
                        goto end;
                    }
                }
            }
        }
    }

end:;

    sprintf(ret, "%lld.%lld.%lld", y, m, d);
    return ret;
}

string ADToMayan(void) {
    long long y, m, d, b, ka, t, w, ki;
    int leap = 0;

    sscanf(s, "%lld.%lld.%lld", &y, &m, &d);
    for(int i = 2013; i < y; i++) if(leapYear(i)) leap++;

    if(leapYear(y) && m > 2) leap++;

    long long dy = 365 * (y - 2013 <= 0 ? 0 : y - 2013) + leap;

    if(y > 2012) {
        dy += 10;
        for(int i = 1; i <= m; i++)
            if(i == m) dy += d;
            else dy += month[i];
    } else dy = d - 21;

    dy %= 1872000;
    b = dy / 144000; dy %= 144000;
    ka = dy / 7200; dy %= 7200;
    t = dy / 360; dy %= 360;
    w = dy / 20; dy %= 20;
    ki = dy;

    sprintf(ret, "%lld.%lld.%lld.%lld.%lld", b, ka, t, w, ki);
    return ret;
}

int main()
{
    string ans;
    while(cin >> s) {
        if(s[0] == '#')
            break;
        int dn = 0;
        for(int i = 0; i < strlen(s); i++) if(s[i] == '.') dn++;

        if(dn == 2) ans = ADToMayan();
        else ans = MayanToAD();

        cout << ans << endl;
    }
}

閏年もO(1)で求めれるらしい…
経過日数の計算 (アルゴリズムとデータ構造)