難しくはないけど、やることが複雑だし、問題文を読み解くのがハードな問題! この手の問題は、解けないと思ったら、実際のコードを見てしまう方が早いと思う。
問題概要
正の整数 が与えられる。
1 から までの数値が書かれたカードがこの順に上から積み上がっている。この山に対して、 回の操作を実行する。各操作は非負整数値 で示され、
とする。 回操作後のカードの山の各数値を答えよ。
考えたこと
特に特別な工夫をすることなく、問題文で言われたことをそのまま実装すれば正解となる。このように「言われたままに実装すればよい」という解法を、愚直シミュレーションと呼ぶことがある。
愚直シミュレーションは軽視されがちではあるものの、今後あらゆるアルゴリズムを実装する上での実装力の礎となる。こうした問題にも真摯に取り組みたいところ。
関数を活用
工夫のしどころとしては、「リフルシャッフル」「整数 でカット」という操作を実行する部分を関数として切り出すと良いと思う。プログラム全体が見やすくなるし、WA が取れないとき、関数の部分だけをテストするなどしてデバッグしやすくなる。
コード
#include <bits/stdc++.h> using namespace std; // 2N 枚のカードをリフルシャッフルする関数 vector<int> rifuru(vector<int> cards, int N) { // 2N 枚のカードを前半と後半に分ける vector<int> zenhan, kouhan; for (int i = 0; i < N; ++i) zenhan.push_back(cards[i]); for (int i = N; i < N*2; ++i) kouhan.push_back(cards[i]); // zenhan と kouhan を互いに違いに入れていく vector<int> res; for (int i = 0; i < N; ++i) { res.push_back(zenhan[i]); res.push_back(kouhan[i]); } return res; } // 整数 k でカットする関数 vector<int> cut(vector<int> cards, int N, int K) { vector<int> res; // 後半 2N-K 枚を先に挿入していく for (int i = K; i < N*2; ++i) res.push_back(cards[i]); // 前半 K 枚を挿入していく for (int i = 0; i < K; ++i) res.push_back(cards[i]); return res; } int main() { int N, M; cin >> N >> M; // 1〜2N のカードを用意する vector<int> cards(N*2, 0); for (int i = 0; i < N*2; ++i) cards[i] = i+1; // 順に実行していく for (int i = 0; i < M; ++i) { int K; cin >> K; if (K == 0) cards = rifuru(cards, N); else cards = cut(cards, N, K); } // 結果を出力 for (int i = 0; i < N*2; ++i) cout << cards[i] << endl; }