けんちょんの競プロ精進記録

競プロの精進記録や小ネタを書いていきます

AtCoder ABC 227 A - Last Card (灰色, 100 点)

これは難しいですね。何も考えずに for 文で求めるのが比較的楽でしょうか。

問題概要

 1, 2, \dots, N と番号のついた  N 人に、 K 枚のカードを配っていく。

 A から始めて、人  A,A+1,A+2,…,N,1,2,… の順に 1 枚ずつカードを配るとき、最後のカードは誰に配られるでしょうか?

 

解法 1:演算子「%」を使用する

上の並びは、「 A から順に 1 ずつ増やしていき、 N+1 になった瞬間に  1リセットする」というようになっています。

ここで、もし仮にリセットがないものとした場合には、答えは  A + K - 1 になります (植木算をしています)。ここが分かりにくいと感じた場合には、具体的な  K の値で確かめてみましょう。

  •  1 番目: A
  •  2 番目: A + 1
  •  3 番目: A + 2
  •  \dots

この並びをみていると、一般に  K 番目は  A K-1 を足したものであることがわかります。よって、 K 番目の値は  A + K - 1 となります。

リセットつき

ここまで来れば、リセットが存在する場合も容易に求められます。基本的には、 A + K - 1 N で引いていき、 N 以下の値になれば、それが答えです。

たとえば、 A + K - 1 = 94 N = 10 であれば、答えは  4 です。 A + K - 1 = 100 N = 10 であれば、答えは  10 です。

 A + K - 1 N で割ってみましょう。

  • 割り切れないときは、その余りが答え
  • 割り切れるときは、 N が答え

と考えれば良いです。

コード

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

int main() {
    int N, K, A;
    cin >> N >> K >> A;
    
    int no_reset = A + K - 1;
    if (no_reset % N > 0)
        cout << no_reset % N << endl;
    else
        cout << N << endl;
}

 

解法 (2)

何も考えずに for 文で書いてもよいでしょう。

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

int main() {
    int N, K, A;
    cin >> N >> K >> A;
    
    int res = A;
    for (int i = 0; i < K - 1; ++i) {
        ++res;
        if (res == N+1) res = 1;
    }
    cout << res << endl;
}