Codeforces Round #334 (Div. 1) B. Moodular Arithmetic
数学あるいはグラフの問題。
B. Moodular Arithmetic
問題
奇素数$p$と非負整数$k \lt p$が与えられる。 以下を満たす関数$f : {0,1,2,\dots,p-1} \to {0,1,2,\dots,p-1}$の数を求めよ。
- $f(kx \bmod p) \equiv k \cdot f(x) \pmod p$
解法
$y \equiv f(x)$と$x$での値を定めると、$ky \equiv kf(x) \equiv f(kx)$と$kx$での値も定まる。 $p$は素数なので、ある$n$があって、$k^n \equiv 1 \pmod p$。$y \equiv k^ny \equiv f(k^ny) \equiv f(y)$と、一巡する。引数と値で矛盾は生じないので確認は不要。つまり、このようなサイクルの数$c$を数え、その数だけサイクルの始点の値の自由度があるため、答えは$p^c$となる。ここで$c = \frac{p-1}{n}$となる。
ただし$k = 0, 1$の場合に注意。
実装
$p$の冪乗は間に合うので線形に書いた。
#include <iostream>
#include <cassert>
#define repeat(i,n) for (int i = 0; (i) < (n); ++(i))
typedef long long ll;
using namespace std;
constexpr ll mod = 1000000007;
int main() {
ll p, k; cin >> p >> k;
ll q = 1;
if (k != 0) {
for (ll t = k; t != 1; t = t * k % p) ++ q;
}
ll result = 1;
if (k == 1) result *= p;
assert ((p - 1) % q == 0);
repeat (i, (p - 1) / q) result = result * p % mod;
cout << result << endl;
return 0;
}