Toy と帽子と ADP BE

主にプログラミングに関わる話をゆるくエモくやっていきます

A. New Year and Naming (Codeforces Hello 2020)

問題

https://codeforces.com/contest/1284/problem/A

問題概要

長さnの文字列の配列s1,s2,s3,...,snと長さmの文字列の配列t1,t2,t3,...,tmが与えられる。

これらの配列から下記のルールでそれぞれ一つずつ文字列を取って結合した新しい文字列を作るとき、y番目にくる文字列を出力せよ。

ルール

1番目はs1 + t1、2番目はs2 + t2のように、それぞれの配列の先頭から順に一文字ずつ取得する。

配列の最後に達した場合、次は先頭に戻る。

配列s = {"a", "b", "c", "d"}、配列t = {"x", "y", "z"}のとき

1 2 3 4 5 6 7 8 9 10
ax by cz dx ay bz cx dy az bx

解説

配列sで考えた時、n番目の次はn+1番目ですがこれは存在しないので1番目に戻ります。これはnの剰余を取れば求められます。

あとは配列のインデックスをどう扱うかですが、0-indexedで扱っておいて、与えられた番号から1を引くのが一番効率がいいようです。

int main() {
    int n, m;
    cin >> n >> m;
    vector<string> s(n);
    vector<string> t(m);
    for (int i = 0; i < n; i++) cin >> s[i];
    for (int i = 0; i < m; i++) cin >> t[i];
    int q;
    cin >> q;
    while (q--) {
        int y;
        cin >> y;
        y--;
        cout << s[y % n] + t[y % m] << endl;
    }
}

私は与えられた番号とインデックスを合わせたかったので、あえて1-indexedで持ちました。しかし、そうするとちょうどnのときに場合分けをしなければならないので、結局楽にはなっていません。

int main() {
    int n, m;
    cin >> n >> m;
    vector<string> s(n + 1);
    vector<string> t(m + 1);
    for (int i = 1; i <= n; i++) cin >> s[i];
    for (int i = 1; i <= m; i++) cin >> t[i];
 
    int q;
    cin >> q;
    while (q--) {
        int y;
        cin >> y;
        // 1-indexedなので、0のときnを持ってこないといけない
        cout << s[y % n == 0 ? n : y % n] + t[y % m == 0 ? m : y % m] << endl;
    }
}

これの亜種として、1-indexedで持つけどn番目は0に入れてしまう、というテクニック?もあるようです。

int main() {
    int n, m;
    cin >> n >> m;
    vector<string> s(n + 1);
    vector<string> t(m + 1);
    for (int i = 1; i < n; i++) cin >> s[i];
    // 前処理で細工をしておく
    cin >> s[0];
    for (int i = 1; i < m; i++) cin >> t[i];
    cin >> t[0];
    int q;
    cin >> q;
    while (q--) {
        int y;
        cin >> y;
        // ここで小細工をする必要がなくなる
        cout << s[y % n] + t[y % m] << endl;
    }
}