というコーナーケースにやられた!
問題概要
整数 が与えられる。
を で割った余りの一の位の値を求めよ。
(マルチテストケース)
制約
考えたこと
まず最初に考えたのは「全体を で割った世界」で考えれば良いということ。
このことを正当化しよう。一般に、次のことが成り立つ。
整数 と正の整数 に対して
であることと、
であることは同値である。
つまり、 を で割った余りを とすると、
と表せるが、これを全体に 倍して得られる
は同値だということだ。
よって、この問題の答えは
を で割った余りを求めて、 をかけた値
となることがわかった。
例外処理
ただし、 の場合は例外なので例外扱いする。
この場合は、 であるから、答えは である。
本題
以降、 とする。そして、「 を で割った余り」を頑張って求める。
ここで、今度は次のことに注目しよう。
相異なる整数 a, b と、整数多項式 に対して、次のことが成り立つ。
つまり、 についての合同式を考えるとき、 の部分をそのまま に置き換えてよいということだ!!!
そうすると、たとえば のとき、次のように式変形できる。
より一般に、 を で割った余りを とすると、次のようになる。
よって、この問題の答えは である。あとは、この値を 10 で割った余りを求めれば OK。
計算量は となる。
コード
#include <bits/stdc++.h> using namespace std; template<class T> T mod_pow(T a, T n, T m) { T res = 1; while (n > 0) { if (n % 2 == 1) res = res * a % m; a = a * a % m; n >>= 1; } return res; }; void solve() { long long N, M, K; cin >> N >> M >> K; if (N < K) { cout << mod_pow(2LL, N, 10LL) << endl; } else { if (M - K == 1) cout << 0 << endl; else cout << mod_pow(2LL, (N - K) % (M - K) + K, 10LL) << endl; } } int main() { int T; cin >> T; while (T--) solve(); }