[CF1252K] Addition Robot 题解

[CF1252K] Addition Robot 题解

传送门

矩阵

对于操作二而言,我们可以将其转换成矩阵的形式,为了避免混淆,以下将原题中的函数参数 A B 替代为 a b

即如果当前是位置 A,执行

\[\begin{pmatrix} b & a \end{pmatrix} · \begin{pmatrix} 1 & 1\\ 0 & 1 \end{pmatrix} = \begin{pmatrix} b & a + b \end{pmatrix} \]

同理可得,如果当前是位置 B,执行

\[\begin{pmatrix} b & a \end{pmatrix} · \begin{pmatrix} 1 & 0\\ 1 & 1 \end{pmatrix} = \begin{pmatrix} b + a & a \end{pmatrix} \]

称矩阵

\[\begin{pmatrix} 1 & 1\\ 0 & 1 \end{pmatrix} \]

\(\alpha\) 矩阵。

矩阵

\[\begin{pmatrix} 1 & 0\\ 1 & 1 \end{pmatrix} \]

\(\beta\) 矩阵。

若将所有为 A 的位置上放上 \(\alpha\) 矩阵,所有为 B 的位置上放上 \(\beta\) 矩阵,则操作二可看作是矩阵

\[\begin{pmatrix} b & a \end{pmatrix} \]

乘上区间 \([l, r]\) 中的矩阵乘积。

可以用线段树维护这个东西。

线段树

考虑如何快速处理区间翻转后的矩阵,手模规律可以发现,区间翻转后的矩阵就变为了原矩阵对角线互换。

具体而言,对于一个线段树节点维护的矩阵

\[\begin{pmatrix} a & b\\ c & d \end{pmatrix} \]

它维护的区间翻转后的矩阵成绩必然为

\[\begin{pmatrix} d & c\\ b & a \end{pmatrix} \]

因此加上懒标记即可完成这题

时间复杂度:\(O(C m\log n)\),其中 \(C = 2^3\),是矩阵乘法所需的常数。

// Problem: Addition Robot
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF1252K
// Memory Limit: 250 MB
// Time Limit: 3000 ms
// Author: Moyou
// Copyright (c) 2023 Moyou All rights reserved.
// Date: 2023-03-08 23:03:12

#include <cstring>
#include <iostream>
#define int long long
#define speedup (ios::sync_with_stdio(0), cin.tie(0), cout.tie(0))
using namespace std;

const int N = 1e5 + 10, mod = 1e9 + 7;

struct mat
{
    int m[3][3];
    int r, c;
    void clear(int R, int C)
    {
        memset(m, 0, sizeof m);
        r = R, c = C;
    }
    void init()
    {
        for(int i = 1; i <= min(r, c); i ++) m[i][i] = 1;
    }
    friend mat operator * (const mat a, const mat b)
    {
        mat res;
        res.clear(a.r, b.c);
        for(int i = 1; i <= a.r; i ++)
            for(int j = 1; j <= b.c; j ++)
                for(int k = 1; k <= a.c; k ++)
                    res.m[i][j] = (a.m[i][k] * b.m[k][j] % mod + res.m[i][j]) % mod;
        return res;
    }
    
    void operator = (const mat a)
    {
        for(int i = 1; i <= a.r; i ++)
            for(int j = 1; j <= a.c; j ++)
                m[i][j] = a.m[i][j];
    }
    
    void print()
    {
        for(int i = 1; i <= r; i ++, cout << endl)
            for(int j = 1; j <= c; j ++)
                cout << m[i][j] << ' ';
    }
    
    void change()
    {
        swap(m[1][1], m[2][2]);
        swap(m[1][2], m[2][1]);
    }
} ;

struct qwq
{
    int l, r;
    mat m;
    bool tag;
} tr[N << 2];

mat alpha, beta;
bool ini[N];

void up(int k)
{
    tr[k].m = tr[k << 1].m * tr[k << 1 | 1].m;
}

void down(int k)
{
    if(!tr[k].tag) return ;
    tr[k << 1].m.change(), tr[k << 1 | 1].m.change();
    tr[k << 1].tag ^= 1, tr[k << 1 | 1].tag ^= 1;
    tr[k].tag = 0;
}

void build(int k, int l, int r)
{
    int mid = l + r >> 1;
    tr[k] = {l, r};
    tr[k].m.clear(2, 2), tr[k].m.init();
    if(l == r) tr[k].m = (ini[l] ? beta : alpha);
    else build(k << 1, l, mid), build(k << 1 | 1, mid + 1, r), up(k);
    // cout << k << ' ' << l << ' ' << r << endl;
    // tr[k].m.print();
}

void update(int k, int ql, int qr)
{
    int l = tr[k].l, r = tr[k].r, mid = l + r >> 1;
    if(ql <= l && qr >= r) 
    {
        tr[k].m.change();
        tr[k].tag ^= 1;
        return ;
    }
    down(k);
    if(ql <= mid) update(k << 1, ql, qr);
    if(qr > mid) update(k << 1 | 1, ql, qr);
    up(k);
}

mat query(int k, int ql, int qr)
{
    int l = tr[k].l, r = tr[k].r, mid = l + r >> 1;
    if(ql <= l && qr >= r) 
        return tr[k].m;
    down(k);
    mat tmp;
    tmp.clear(2, 2), tmp.init();
    if(ql <= mid) tmp = tmp * query(k << 1, ql, qr);
    if(qr > mid) tmp = tmp * query(k << 1 | 1, ql, qr);
    return tmp;
}

signed main()
{
    speedup;
    int n, q;
    cin >> n >> q;
    alpha.clear(2, 2);
    alpha.m[1][1] = alpha.m[1][2] = alpha.m[2][2] = 1;
    beta.clear(2, 2);
    beta.m[1][1] = beta.m[2][1] = beta.m[2][2] = 1;
    string s;
    cin >> s;
    for(int i = 1; i <= n; i ++)
    {
        if(s[i - 1] == 'A') ini[i] = 0;
        else ini[i] = 1;
    }
    
    build(1, 1, n);
    
    mat A;
    A.clear(1, 2);
    
    while(q --)
    {
        int op;
        cin >> op;
        if(op == 1)
        {
            int l, r;
            cin >> l >> r;
            update(1, l, r);
        }
        else 
        {
            int l, r, a, b;
            cin >> l >> r >> a >> b;
            A.m[1][2] = a, A.m[1][1] = b;
            A = (A * query(1, l, r));
            cout << A.m[1][2] << ' ' << A.m[1][1] << "\n";
        }
    }

    return 0;
}
posted @ 2023-03-09 00:12  MoyouSayuki  阅读(15)  评论(0编辑  收藏  举报
:name :name