题意:
Yelekastee 是 U 国著名的考古学家。在最近的一次考古行动中,他发掘出了一个远古时期的密码箱。经过周密而严谨的考证,Yelekastee 得知密码箱的密码和某一个数列 \(\{ a_n \}\) 相关。数列 \(\{ a_n \}\) 可以用如下方式构造出来:
- 初始时数列长度为 \(2\) 且有 \(a_0 = 0, a_1 = 1\);
- 对数列依次进行若干次操作,其中每次操作是以下两种类型之一:
W
类型:给数列的最后一项加 \(1\)。E
类型:若数列的最后一项为 \(1\),则给倒数第二项加 \(1\);否则先给数列的最后一项减 \(1\),接着在数列尾再加两项,两项的值都是 \(1\)。
受到技术限制,密码箱并没有办法完整检查整个数列,因此密码箱的密码设定为数列 \(\{ a_n \}\) 经过函数 \(f\) 作用后的值,其中 \(f\) 的定义如下:
\[f(a_0, \ldots , a_{k - 1}, a_k) = \begin{cases} a_0, & k = 0 \\ f \! \left( a_0, a_1, \ldots , a_{k - 2}, a_{k - 1} + \frac{1}{a_k} \right) \! , & k \ge 1 \end{cases} \]Yelekastee 并不擅长运算,因此他找到了你,希望你能根据他提供的操作序列计算出密码箱的密码。不幸的是,他的记性并不是很好,因此他会随时对提供的操作序列做出一些修改,这些修改包括以下三种:
APPEND c
,在现有操作序列后追加一次c
类型操作,其中c
为字符W
或E
。FLIP l r
,反转现有操作序列中第 \(l\) 个至第 \(r\) 个(下标从 \(1\) 开始,修改包含端点 \(l\) 和 \(r\),下同)操作,即所有W
变为E
,所有E
变为W
。REVERSE l r
,翻转现有操作序列中第 \(l\) 个至第 \(r\) 个操作,也就是将这个区间中的操作逆序。
分析:
发现 \(f\) 的倒数形如:
\[\frac{1}{a_{0}+\frac{1}{a_{1}+\frac{1}{a_{2}+\dots}}} \]考虑从右往左加入 \(a_{i}\),将 \(\frac{a}{b} \rightarrow \frac{A}{B}\):
\[\frac{A}{B}=\frac{1}{a_{i}+\frac{a}{b}} \]可以发现 \(A=b,\ B=a_{i} \times b+a\)。
似乎可以使用矩阵乘法。
\[\begin{bmatrix} A \\ B \end{bmatrix} = \begin{bmatrix} 0 & 1 \\ 1 & a_{i} \end{bmatrix} \times \begin{bmatrix} a \\ b \end{bmatrix} \]最后答案即为:
\[\begin{bmatrix} 0 & 1 \\ 1 & a_{0} \end{bmatrix} \times \begin{bmatrix} 0 & 1 \\ 1 & a_{1} \end{bmatrix} \times \begin{bmatrix} 0 & 1 \\ 1 & a_{2} \end{bmatrix} \times \dots \times \begin{bmatrix} 0 & 1 \\ 1 & a_{3} \end{bmatrix} \times \begin{bmatrix} 0 \\ 1 \end{bmatrix} \]不难构造出,\(W\) 操作就是在后面乘上 \(\begin{bmatrix} 1 & 1 \\ 0 & 1 \end{bmatrix}\),\(E\) 操作就是在后面乘上 \(\begin{bmatrix} 0 & -1 \\ 1 & 2 \end{bmatrix}\)。
由于有翻转操作和取反操作,因此可以使用 FHQ-Treap 来维护。
具体地,平衡树每个节点维护以下信息:
-
该节点的类型(是 \(W\) 还是 \(E\))。
-
子树内的矩阵连乘积。
-
子树内的翻转矩阵连乘积。
-
子树内的取反矩阵连乘积。
-
子树内的翻转取反矩阵连乘积。
-
子树内的翻转标记。
-
子树内的取反标记。
标记的合并只需要异或 \(1\) 即可。时间复杂度 \(O(n \log n)\)。常数巨大,轻度卡常。
代码:
#include<bits/stdc++.h>
#define N 200005
#define mod 998244353
#define ll long long
using namespace std;
struct node {
int n, m;
int a[5][5];
friend node operator * (node x, node y) {
node z;
if(x.n == 2 && x.m == 2 && y.n == 2 && y.m == 2) {
z.n = z.m = 2;
z.a[1][1] = 1ll * ((long long)1ll * x.a[1][1] * y.a[1][1] % mod + (long long)1ll * x.a[1][2] * y.a[2][1] % mod + mod) % mod;
z.a[1][2] = 1ll * ((long long)1ll * x.a[1][1] * y.a[1][2] % mod + (long long)1ll * x.a[1][2] * y.a[2][2] % mod + mod) % mod;
z.a[2][1] = 1ll * ((long long)1ll * x.a[2][1] * y.a[1][1] % mod + (long long)1ll * x.a[2][2] * y.a[2][1] % mod + mod) % mod;
z.a[2][2] = 1ll * ((long long)1ll * x.a[2][1] * y.a[1][2] % mod + (long long)1ll * x.a[2][2] * y.a[2][2] % mod + mod) % mod;
return z;
}
else {
z.n = 2; z.m = 1;
z.a[1][1] = 1ll * ((long long)1ll * x.a[1][1] * y.a[1][1] % mod + (long long)1ll * x.a[1][2] * y.a[2][1] % mod + mod) % mod;
z.a[2][1] = 1ll * ((long long)1ll * x.a[2][1] * y.a[1][1] % mod + (long long)1ll * x.a[2][2] * y.a[2][1] % mod + mod) % mod;
return z;
}
}
};
void Out(node X) {
cout << endl;
for(int i = 1; i <= X.n; i++) {
for(int j = 1; j <= X.m; j++) cout << X.a[i][j] << " ";
cout << endl;
}
cout << endl;
}
node Empty() {
node now;
now.n = now.m = 2;
now.a[1][1] = now.a[2][2] = 1;
now.a[1][2] = now.a[2][1] = 0;
return now;
}
int n, Q, root, cnt;
int ls[N], rs[N], siz[N], pri[N];
node My[N];
char r[N];
node val[N], val_f[N], val_r[N], val_fr[N];
bool tagf[N], tagr[N]; //f:是否取反 r:是否翻转
node W, E, P, X;
int newnode(char opt) {
cnt++;
siz[cnt] = 1;
pri[cnt] = rand() * rand();
if(opt == 'E') {
val[cnt] = val_r[cnt] = E;
val_f[cnt] = val_fr[cnt] = W;
}
else {
val[cnt] = val_r[cnt] = W;
val_f[cnt] = val_fr[cnt] = E;
}
My[cnt] = val[cnt];
r[cnt] = opt;
return cnt;
}
void pushup(int u) {
siz[u] = siz[ls[u]] + siz[rs[u]] + 1;
val[u] = val[ls[u]] * My[u] * val[rs[u]];
node now;
if(r[u] == 'E') now = W;
else now = E;
val_f[u] = val_f[ls[u]] * now * val_f[rs[u]];
val_r[u] = val_r[rs[u]] * My[u] * val_r[ls[u]];
val_fr[u] = val_fr[rs[u]] * now * val_fr[ls[u]];
}
void maketag(int u, bool F, bool R) { //Flip, Revserse,
node A = val[u], B = val_r[u], C = val_f[u], D = val_fr[u];
if(!F && R) { //只翻转
swap(ls[u], rs[u]);
val[u] = B;
val_r[u] = A;
val_f[u] = D;
val_fr[u] = C;
tagr[u] ^= 1;
}
else if(F && !R) { //只取反
val[u] = C;
val_r[u] = D;
val_f[u] = A;
val_fr[u] = B;
tagf[u] ^= 1;
if(r[u] == 'E') {
r[u] = 'W';
My[u] = W;
}
else {
r[u] = 'E';
My[u] = E;
}
}
else if(F && R) { //取反+翻转
swap(ls[u], rs[u]);
val[u] = D;
val_r[u] = C;
val_f[u] = B;
val_fr[u] = A;
tagf[u] ^= 1;
tagr[u] ^= 1;
if(r[u] == 'E') {
r[u] = 'W';
My[u] = W;
}
else {
r[u] = 'E';
My[u] = E;
}
}
}
void pushdown(int u) {
maketag(ls[u], tagf[u], tagr[u]);
maketag(rs[u], tagf[u], tagr[u]);
tagf[u] = tagr[u] = 0;
}
int merge(int x, int y) {
if(x == 0 || y == 0) return x + y;
pushdown(x); pushdown(y);
if(pri[x] < pri[y]) {
rs[x] = merge(rs[x], y);
pushup(x);
return x;
}
else {
ls[y] = merge(x, ls[y]);
pushup(y);
return y;
}
}
void split(int u, int &x, int &y, int k) {
if(u == 0) {
x = y = 0;
return;
}
pushdown(u);
if(k <= siz[ls[u]]) {
y = u;
split(ls[u], x, ls[u], k);
}
else {
x = u;
split(rs[u], rs[u], y, k - siz[ls[u]] - 1);
}
pushup(u);
}
void Insert(char opt) {
root = merge(root, newnode(opt));
}
string S, opt;
void Flip(int l, int r) {
int x, y, z;
split(root, x, y, l - 1);
split(y, y, z, r - l + 1);
maketag(y, 1, 0);
root = merge(merge(x, y), z);
}
void Reverse(int l, int r) {
int x, y, z;
split(root, x, y, l - 1);
split(y, y, z, r - l + 1);
maketag(y, 0, 1);
root = merge(merge(x, y), z);
}
void Print() {
node Ans = P * val[root] * X;
cout << Ans.a[2][1] << " " << Ans.a[1][1] << endl;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
val[0] = val_f[0] = val_r[0] = val_fr[0] = Empty();
W.n = W.m = E.n = E.m = P.n = P.m = 2;
W.a[1][1] = 1; W.a[1][2] = 1; W.a[2][1] = 0; W.a[2][2] = 1;
E.a[1][1] = 0; E.a[1][2] = -1; E.a[2][1] = 1; E.a[2][2] = 2;
P.a[1][1] = 1; P.a[1][2] = 1; P.a[2][1] = 0; P.a[2][2] = 1;
X.n = 2; X.m = 1;
X.a[1][1] = 0; X.a[2][1] = 1;
cin >> n >> Q >> S;
for(int i = 0; i < n; i++) Insert(S[i]);
Print();
while(Q--) {
cin >> opt;
if(opt[0] == 'A') { //append
char c;
cin >> c;
Insert(c);
}
else if(opt[0] == 'F') {
int l, r;
cin >> l >> r;
Flip(l, r);
}
else {
int l, r;
cin >> l >> r;
Reverse(l, r);
}
Print();
}
return 0;
}
标签:begin,P7739,end,密码箱,long,NOI2021,1ll,bmatrix,mod
From: https://www.cnblogs.com/xcs123/p/18144616