CF1252K Addition Robot 题解

题目链接

思路

对于 \(A = A + B\)\(B = A + B\) 这种的递推式可以考虑矩阵加速递推,可得:

\[\left ( \begin{matrix} A + B & B \end{matrix} \right ) = \left ( \begin{matrix} A & B \end{matrix} \right ) \left ( \begin{matrix} 1 & 0 \\ 1 & 1 \end{matrix} \right ) \]

\[\left ( \begin{matrix} A & A + B \end{matrix} \right ) = \left ( \begin{matrix} A & B \end{matrix} \right ) \left ( \begin{matrix} 1 & 1 \\ 0 & 1 \end{matrix} \right ) \]

\(A,B\) 二元组看作单位向量 \(\left ( \begin{matrix} A & B \end{matrix} \right )\),设 \(S_i\) 对应的转移矩阵为 \(G_i\),则一次 F 函数操作得到的 \(A,B\) 二元组对应的向量就是:

\[\left ( \begin{matrix} A & B \end{matrix} \right ) \prod_{i = l}^{r} G_i \]

由于矩阵乘法满足结合律,对于一段区间的矩阵的乘积,我们可以用线段树维护。

考虑区间取反操作怎么实现,我们通过打表观察上方给出的两个转移矩阵,发现它们都是对方旋转了 \(180^{\circ}\)。感性理解一下,设有矩阵 \(A,B,C\),有:

\[A = \left ( \begin{matrix} a_1 & b_1 \\ c_1 & d_1 \end{matrix} \right ) \]

\[B = \left ( \begin{matrix} a_2 & b_2 \\ c_2 & d_2 \end{matrix} \right ) \]

\[C = A \times B = \left ( \begin{matrix} a_1a_2 + b_1c_2 & a_1b_2 + b_1d_2 \\ c_1a_2 + d_1c_2 & c_1b_2 + d_1d_2 \end{matrix} \right ) \]

\(A'\)\(B'\)\(A\)\(B\) 各旋转 \(180^{\circ}\) 后的矩阵,有:

\[A' = \left ( \begin{matrix} d_1 & c_1 \\ b_1 & a_1 \end{matrix} \right ) \]

\[B' = \left ( \begin{matrix} d_2 & c_2 \\ b_2 & a_2 \end{matrix} \right ) \]

\[C' = A' \times B' = \left ( \begin{matrix} d_1d_2 + c_1b_2 & d_1c_2 + c_1a_2 \\ b_1d_2 + a_1b_2 & b_1c_2 + a_1a_2 \end{matrix} \right ) \]

可以发现 \(C'\) 也是 \(C\) 旋转 \(180^{\circ}\) 后的结果,所以推广这个结论到 \(A,B\) 的反转操作上,就是直接交换矩阵对角线上的元素。就像维护01序列的翻转那样维护线段树就行了。时间复杂度 \(\Theta (2 ^ 3 n \log n)\)

Code

#include<cstdio>
#include<cstring>
#include<algorithm>

#define LL long long

using namespace std;

const int Mod = 1e9 + 7;
const int MAXN = 1e5 + 10, SIZE = 3;
int n, q;
char s[MAXN];

struct Matrix{
    int hig, wid;
    LL num[SIZE][SIZE];

    Matrix(){
        hig = wid = 0;
        memset(num, 0, sizeof(num));
    }

    Matrix operator * (const Matrix &b) const{
        Matrix c;
        c.hig = hig, c.wid = b.wid;
        for(register int i = 1; i <= c.hig; i++){
            for(register int k = 1; k <= b.hig; k++){
                LL res = num[i][k];
                for(register int j = 1; j <= c.wid; j++)
                    c.num[i][j] = 1LL * (c.num[i][j] + res * b.num[k][j] % Mod) % Mod;
            }
        }

        return c;
    }

    void Reverse(){
        swap(num[1][1], num[2][2]);
        swap(num[1][2], num[2][1]);
    }
}base, G1, G2, I;

struct Segment_Tree{
    struct Tree{
        int l, r;
        Matrix sum;
        int lazy;
    }tr[MAXN << 2];

    inline int lson(int rt){
        return rt << 1;
    }

    inline int rson(int rt){
        return rt << 1 | 1;
    }

    inline void Pushup(int rt){
        tr[rt].sum = tr[lson(rt)].sum * tr[rson(rt)].sum;
    }

    void Build(int rt, int l, int r){
        tr[rt].l = l, tr[rt].r = r;
        if(l == r){
            if(s[l] == 'A') tr[rt].sum = G1;
            else tr[rt].sum = G2;
            return;
        }

        int mid = (l + r) >> 1;
        Build(lson(rt), l, mid);
        Build(rson(rt), mid + 1, r);

        Pushup(rt);
    }

    inline void Pushdwon(int rt){
        if(tr[rt].lazy){
            tr[lson(rt)].lazy ^= 1;
            tr[rson(rt)].lazy ^= 1;
            tr[lson(rt)].sum.Reverse();
            tr[rson(rt)].sum.Reverse();
            tr[rt].lazy = 0;
        }
    }

    void Update_Rev(int rt, int l, int r){
        if(tr[rt].l >= l && tr[rt].r <= r){
            tr[rt].sum.Reverse();
            tr[rt].lazy ^= 1;
            return;
        }

        Pushdwon(rt);

        int mid = (tr[rt].l + tr[rt].r) >> 1;
        if(l <= mid) Update_Rev(lson(rt), l, r);
        if(r > mid) Update_Rev(rson(rt), l, r);

        Pushup(rt);
    }

    Matrix Query_Sum(int rt, int l, int r){
        if(tr[rt].l >= l && tr[rt].r <= r) return tr[rt].sum;

        Pushdwon(rt);

        Matrix ans = base;
        int mid = (tr[rt].l + tr[rt].r) >> 1;
        if(l <= mid) ans = ans * Query_Sum(lson(rt), l, r);
        if(r > mid) ans = ans * Query_Sum(rson(rt), l, r);

        return ans;
    }
}S;

void init(){
    base.hig = base.wid = 2;
    base.num[1][1] = base.num[2][2] = 1;
    G1.hig = G1.wid = 2;
    G1.num[1][1] = G1.num[2][1] = G1.num[2][2] = 1;
    G2.hig = G2.wid = 2;
    G2.num[1][1] = G2.num[1][2] = G2.num[2][2] = 1;
    I.hig = 1, I.wid = 2;
}

int main(){
    init();

    scanf("%d%d", &n, &q);
    scanf("%s", s + 1);

    S.Build(1, 1, n);

    for(register int i = 1; i <= q; i++){
        int opt;
        scanf("%d", &opt);

        if(opt == 1){
            int l, r;
            scanf("%d%d", &l, &r);
            S.Update_Rev(1, l, r);
        }
        else{
            int l, r, a, b;
            scanf("%d%d%d%d", &l, &r, &a, &b);
            I.num[1][1] = a, I.num[1][2] = b;
            I = I * S.Query_Sum(1, l, r);
            printf("%lld %lld\n", I.num[1][1], I.num[1][2]);
        }
    }

    return 0;
}

马蜂冗长,不喜勿喷。

posted @ 2022-11-11 21:34  TSTYFST  阅读(35)  评论(0编辑  收藏  举报