Codeforces 385(#226 Div2 only) E. Bear in the Field
問題
nxnのグリッドがあって、最初(sx, sy)にいる。
最初の速度は(dx, dy)で、速度(dx, dy)で移動すると、
x' = (x + dx - 1) mod n + 1
y' = (y + dy - 1) mod n + 1に移動する。
移動の前に、今いるグリッドを(x, y)とすると、dx, dyがともに(今のターン数) + x + yずつ増える。
tターン繰り返した後の位置を求めよ。
制約条件
n≦10^9
t≦10^18
座標は1-origin
方針
(x, y, dx, dy, t)から次のターンの状態を表してみると、
x' = x + (x + y + t) + dx
y' = y + (x + y + t) + dy
dx'= dx + x + y + t
dy'= dy + x + y + t
t' = t + 1
なので、この移動は行列で表せて、
行列の繰り返し二乗法を使えば、tターン後の状態がO(log t)で求まる。
ソースコード
int mod; typedef vector<vi> M; inline M operator*(const M & a, const M &b){ M c(a.size(), vi(b[0].size())); rep(i, c.size()) rep(j, c[0].size()){ ll s = 0; rep(k, a[0].size()) s += (ll)a[i][k] * b[k][j] % mod; c[i][j] = s % mod; if(c[i][j] == 0) c[i][j] = mod; } return c; } inline M pow(M a, ll m){ M res(a.size(), vi(a.size())); rep(i, a.size()) res[i][i] = 1; for(; m; m /= 2){ if(m & 1) res = res * a; a = a * a; } return res; } int main(){ M A(6, vi(6)); int a[6][6] ={ {2, 1, 1, 0, 1, 0}, {1, 2, 0, 1, 1, 0}, {1, 1, 1, 0, 1, 0}, {1, 1, 0, 1, 1, 0}, {0, 0, 0, 0, 1, 1}, {0, 0, 0, 0, 0, 1} }; rep(i, 6) rep(j, 6) A[i][j] = a[i][j]; ll sx, sy, dx, dy, t; M b(6, vi(1)); cin >> mod >> sx >> sy >> dx >> dy >> t; b[0][0] = sx; b[1][0] = sy; b[2][0] = dx; b[3][0] = dy; b[4][0] = 0; b[5][0] = 1; rep(i, 6) b[i][0] = (b[i][0] % mod + mod) % mod; b = pow(A, t) * b; cout << b[0][0] << " " << b[1][0] <<endl; return 0; }