CF1252K Addition Robot 题解
题目链接
思路
对于 , 这种的递推式可以考虑矩阵加速递推,可得:
把 二元组看作单位向量 ,设 对应的转移矩阵为 ,则一次 F
函数操作得到的 二元组对应的向量就是:
由于矩阵乘法满足结合律,对于一段区间的矩阵的乘积,我们可以用线段树维护。
考虑区间取反操作怎么实现,我们通过打表观察上方给出的两个转移矩阵,发现它们都是对方旋转了 。感性理解一下,设有矩阵 ,有:
设 , 为 , 各旋转 后的矩阵,有:
可以发现 也是 旋转 后的结果,所以推广这个结论到 的反转操作上,就是直接交换矩阵对角线上的元素。就像维护01序列的翻转那样维护线段树就行了。时间复杂度 。
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; }
马蜂冗长,不喜勿喷。
以下为博客签名,与博文无关。
只要你们不停下来,那前面就一定有我。所以啊,不要停下来~
本文来自博客园,作者:TSTYFST,转载请注明原文链接:https://www.cnblogs.com/TSTYFST/p/16882112.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理