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;
}
马蜂冗长,不喜勿喷。
以下为博客签名,与博文无关。
只要你们不停下来,那前面就一定有我。所以啊,不要停下来~
本文来自博客园,作者:TSTYFST,转载请注明原文链接:https://www.cnblogs.com/TSTYFST/p/16882112.html