首页 > 其他分享 >CF1252K Addition Robot 题解

CF1252K Addition Robot 题解

时间:2022-11-11 21:45:35浏览次数:115  
标签:rt begin right end matrix Addition 题解 int CF1252K

题目链接

思路

对于 \(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;
}

马蜂冗长,不喜勿喷。

标签:rt,begin,right,end,matrix,Addition,题解,int,CF1252K
From: https://www.cnblogs.com/TSTYFST/p/16882112.html

相关文章

  • P5443 [APIO2019] 桥梁 题解
    容易得出一种暴力算法:将询问按\(w\)排序,将没有修改的边按\(d\)排序。对于每个询问\((t_i,s_i,w_i)\),做两部分操作(这里\(t\)是时间的意思):将没有修改的边中满足\(d......
  • P1587 [NOI2016] 循环之美 题解
    P1587[NOI2016]循环之美这道题我推到后面推不下去了,最后还是看了题解。还是切不了这种题唉。前置知识:杜教筛开始时看不出什么,我们先用经验和手玩来找一下规律。我们......
  • P6628 [省选联考 2020 B 卷] 丁香之路 题解
    图论、贪心好题。枚举每一个朋友,设一个朋友从\(s\)出发,到\(t\)结束。那么如果用边来表示其行动轨迹,必然是\(s,t\)有奇数度,其它点均为偶数度。如果在\(s,t\)之间连......
  • CF464D World of Darkraft - 2 题解
    期望好题,可以帮助我们更加深入地了解期望。由于\(k\)种装备相同,所以只要计算卖掉一种装备得到的金币期望乘以\(k\)就行了。为了避免讨论当前状态的概率,期望DP通常......
  • CF1316E Team Building 题解
    可能更好的阅读体验题目传送门题目大意传送门你需要组建一支排球队。为了组织一支排球队,你需要为队伍里的\(p\)个不同的位置,从\(n\)个人中选出\(p\)个人,且每个位......
  • CF1735E题解
    钦定\(p_1=0,p_2>0\),不难证明如果有解则一定存在\(p_2>p_1\)的解。考虑枚举和\(d_{1,1}\)是相同楼房,则\(p_2\)对于每一种情况有两种可能的位置:\(d_{1,1}+d_{2,i}\)......
  • P3188 [HNOI2007]梦幻岛宝珠 题解
    一道不错的dp题,下令原背包容量为\(m\)。注意到\(w_i=a\times2^b\)中\(a,b\)都比较小,尝试按照\(a\)或者\(b\)分组然后合并,但是显然如果我们按照\(a\)分组就......
  • 汉诺塔问题及其变种问题解法(cpp版本)
    普通汉诺塔问题1.问题描述有三个柱子A、B、C,A柱子上有n个圆盘,圆盘的大小不等,大圆盘的在下,小圆盘的在上。将A柱子上的圆盘全部移动到C柱子上。每次只能移动一个圆盘,而且......
  • 【题解】P2260 [清华集训2012]模积和(数学,整除分块)
    【题解】P2260[清华集训2012]模积和比较简单的一道推式子的题。(清华集训居然会出这种水题的吗)题目链接P2260[清华集训2012]模积和题意概述求\[\sum_{i=1}^{n}\sum......
  • 【题解】CF1485C Floor and Mod(二分答案,整除分块)
    【题解】CF1485CFloorandModemmm……NOIP考前两周,跟CSP考前一样(虽然最后并没有去考),写篇题解增加以下RP(雾)。提供一篇思路大体和题解区相同但用了二分写法的题解。......