SRM 230 DIV1 Hard MultiReplacer
問題
(f: string -> string)は、全ての出現するaをarepに置き換え、bをbrepに置き換え、cをcrepに置き換える(同時に)。
(length (f^iter("a")) mod m)を求めよ。ただし(f^n)はfをn回適用する関数とする。
- arep, brep, crepはa,b,cからなる1から50文字の文字列
- 1 <= iter <= 2*10^9
- 2 <= m <= 2^31-1
解答
行列累乗するだけ。
ベクトルは{aの文字数, bの文字数, cの文字数}(それぞれmod m)
コード
#include <string> #include <vector> #include <algorithm> #define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i)) #define all(o) (o).begin(), (o).end() using namespace std; typedef long long ll; typedef vector<ll> Vec; typedef vector<Vec> Mat; ll MOD; Mat identityMat(int n) { Mat A(n, Vec(n)); rep(i, n) A[i][i] = 1; return A; } Mat multiply(const Mat& A, const Mat& B) { int n = A.size(), m = B[0].size(), p = B.size(); Mat C(n, Vec(m)); rep(i, n) rep(j, m) rep(k, p) { (C[i][j] += A[i][k] * B[k][j]) %= MOD; } return C; } Mat power(const Mat& A, ll n) { return n == 0 ? identityMat(A.size()) : (n & 1) ? multiply(A, power(A, n-1)) : power(multiply(A, A), n>>1); } struct MultiReplacer { long long length(string arep, string brep, string crep, int iter, int m) { MOD = m; Mat A(3, Vec(3, 0)); string reps[3] = {arep, brep, crep}; rep(i, 3) rep(j, 3) A[i][j] = count(all(reps[i]), 'a'+j); Mat V(1, Vec(3, 0)); V[0][0] = 1; V = multiply(V, power(A, iter)); return (V[0][0] + V[0][1] + V[0][2]) % MOD; } };