はまやんはまやんはまやん

hamayanhamayan's blog

ドットちゃんたち [yukicoder No.675]

https://yukicoder.me/problems/no/675

解法

https://yukicoder.me/submissions/251217

このサイトを見ると回転行列と平行移動行列がある事がわかる。
行列は行列通しを先に計算しておくことで、複数の行列を一気に適用することが出来る。
最初の答えは(PX, PY)にクエリ1, クエリ2, .. クエリNを適用する。
次の答えは(PX, PY)にクエリ2, .. クエリNを適用する。
次の答えは(PX, PY)にクエリ3, .. クエリNを適用する。
よって答えに適用するクエリの行列は後ろに行くほど少なくなる。
なので、後ろから答えを確定していくことにしよう。
i番目の答えを作るときは、クエリi, クエリi+1, ..., クエリNを適用する必要があるが、i+1番目の答えを作るための行列をm[i+1]とすると、クエリiとm[i+1]を掛け合わせることでm[i]が作れる。
これで後ろから順に答えを確定していって、最後にちゃんとした順番で答える。

int N, PX, PY, A[101010], B[101010];
ll ansx[101010], ansy[101010];
//---------------------------------------------------------------------------------------------------
void _main() {
    cin >> N >> PX >> PY;
    rep(i, 0, N) {
        cin >> A[i];
        if (A[i] != 3) cin >> B[i];
    }

    Mat m(3, Vec(3, 0));
    rep(i, 0, 3) m[i][i] = 1;

    rrep(i, N - 1, 0) {
        Vec v(3, 0);
        v[0] = PX;
        v[1] = PY;
        v[2] = 1;

        Mat mm(3, Vec(3, 0));
        if (A[i] == 1) {
            mm[0][0] = 1;
            mm[0][2] = B[i];
            mm[1][1] = 1;
            mm[2][2] = 1;
        }
        else if (A[i] == 2) {
            mm[0][0] = 1;
            mm[1][1] = 1;
            mm[1][2] = B[i];
            mm[2][2] = 1;
        }
        else {
            mm[0][0] = 0;
            mm[0][1] = 1;
            mm[1][0] = -1;
            mm[1][1] = 0;
            mm[2][2] = 1;
        }

        m = mulMatMat(m, mm);
        v = mulMatVec(m, v);

        ansx[i] = v[0];
        ansy[i] = v[1];
    }

    rep(i, 0, N) printf("%lld %lld\n", ansx[i], ansy[i]);
}