Addition Robot
直接做是难的,发现这个东西似乎可以矩阵优化。
可以发现
对于
那么对于询问
容易发现可以线段树维护矩阵乘法。
对于区间反转,只需要维护区间反转后的乘积和反转前的乘积,反转时交换两个结果即可。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
using namespace std;
const int N = 1e5 + 5;
const long long MOD = 1e9 + 7;
string s;
int n, m;
struct Matrix
{
long long a[3][3];
Matrix(long long ax, long long b, long long c, long long d)
{
a[1][1] = ax, a[1][2] = b, a[2][1] = c, a[2][2] = d;
}
Matrix()
{
a[0][0] = a[0][1] = a[0][2] = a[1][0] = a[1][1] = a[1][2] = a[2][0] = a[2][1] = a[2][2] = 0LL;
}
void Clear()
{
a[1][1] = -1LL;
}
friend Matrix operator*(const Matrix& a, const Matrix& b)
{
if (a.a[1][1] == -1LL) return b;
if (b.a[1][1] == -1LL) return a;
Matrix c;
for (int i = 1; i <= 2; i++)
{
for (int j = 1; j <= 2; j++)
{
for (int k = 1; k <= 2; k++)
{
c.a[i][j] = (c.a[i][j] + a.a[i][k] * b.a[k][j]) % MOD;
}
}
}
return c;
}
};
class SegmentTree
{
public:
struct Node
{
int l, r;
Matrix ans1, ans2;
bool revtag;
}tr[N << 2];
void pushup(int u)
{
tr[u].ans1 = tr[u << 1].ans1 * tr[u << 1 | 1].ans1;
tr[u].ans2 = tr[u << 1].ans2 * tr[u << 1 | 1].ans2;
}
void pushdown(int u)
{
if (tr[u].revtag)
{
tr[u].revtag = 0;
swap(tr[u << 1].ans1, tr[u << 1].ans2);
tr[u << 1].revtag ^= 1;
swap(tr[u << 1 | 1].ans1, tr[u << 1 | 1].ans2);
tr[u << 1 | 1].revtag ^= 1;
}
}
void build(int u, int l, int r)
{
if (l == r)
{
tr[u] = { l, r };
char c = s[l - 1];
if (c == 'A')
{
tr[u].ans1 = Matrix(1LL, 0LL, 1LL, 1LL);
tr[u].ans2 = Matrix(1LL, 1LL, 0LL, 1LL);
}
else
{
tr[u].ans2 = Matrix(1LL, 0LL, 1LL, 1LL);
tr[u].ans1 = Matrix(1LL, 1LL, 0LL, 1LL);
}
return;
}
tr[u] = { l, r };
int mid = l + r >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
pushup(u);
}
void update(int u, int l, int r)
{
if (tr[u].l >= l and tr[u].r <= r)
{
tr[u].revtag ^= 1;
swap(tr[u].ans1, tr[u].ans2);
return;
}
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid) update(u << 1, l, r);
if (r > mid) update(u << 1 | 1, l, r);
pushup(u);
}
Matrix query(int u, int l, int r)
{
if (tr[u].l >= l and tr[u].r <= r)
{
return tr[u].ans1;
}
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
Matrix res;
res.Clear();
if (l <= mid) res = query(u << 1, l, r);
if (r > mid) res = res * query(u << 1 | 1, l, r);
return res;
}
}tr;
int main()
{
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
cin >> n >> m >> s;
tr.build(1, 1, n);
while (m--)
{
int opt;
cin >> opt;
if (opt == 1)
{
int l, r;
cin >> l >> r;
tr.update(1, l, r);
}
else
{
int l, r;
long long a, b;
cin >> l >> r >> a >> b;
Matrix res(a, b, 0LL, 0LL);
res = res * tr.query(1, l, r);
Matrix p = tr.query(1, l, r);
printf("%lld %lld\n", res.a[1][1], res.a[1][2]);
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现