「Fibonacci Additions」Solution
题意简述
给定两个长度为
n
n
n 序列
a
,
b
a,b
a,b,以及模数
M
O
D
MOD
MOD。
试支持以下操作:
给定
l
,
r
l,r
l,r,对于
∀
i
∈
[
l
,
r
]
,
a
[
i
]
←
a
[
i
]
+
f
[
l
−
i
+
1
]
\forall i \in [l,r],a[i] \leftarrow a[i] + f[l-i+1]
∀i∈[l,r],a[i]←a[i]+f[l−i+1],其中
f
f
f 为斐波那契数列(
f
1
=
f
2
=
1
f_1=f_2=1
f1=f2=1)。
进行
q
q
q 次操作,每次对
a
a
a 或者
b
b
b 进行操作,回答每次操作后
a
a
a 与
b
b
b 数组在模意义下是否相等
- 1 ≤ n , q ≤ 3 × 1 0 5 , 1 ≤ M O D ≤ 1 0 9 + 7 1 \le n ,q\le 3 \times 10^5,1 \le MOD \le 10^9+7 1≤n,q≤3×105,1≤MOD≤109+7
思路
难度 2700,很好的一道差分题。
考虑转化题意,不妨令
c
i
=
a
i
−
b
i
c_i = a_i-b_i
ci=ai−bi,则当且仅当
∀
i
∈
[
1
,
n
]
\forall i \in [1,n]
∀i∈[1,n] 都有
c
i
=
0
c_i=0
ci=0,
a
a
a 与
b
b
b 才相等。即判断
c
c
c 中
0
0
0 元素的个数是否等于
n
n
n。
注意到操作很棘手,
c
c
c 序列难以直接维护,考虑差分。
此题需要对差分有很深入的理解,所以给出几点 tips \text{tips} tips:
- Hint1:差分数组与 c c c 数组有什么关系?
- Hint2:差分数组本质是在维护什么?
- Hint3:该如何定义差分数组才能简化计算?
差分数组实质上是在维护一个增量序列。对于此题,注意到斐波那契数列有强递推式 f i = f i − 1 + f i − 2 f_i=f_{i-1}+f_{i-2} fi=fi−1+fi−2,因此,很自然地想到通过差分抵消中间项,形式化定义如下:
d i = c i − c i − 1 − c i − 2 d_i=c_i-c_{i-1}-c_{i-2} di=ci−ci−1−ci−2
那么,每次操作就等价于:
d
l
←
d
l
+
f
1
,
d
r
+
1
←
d
r
+
1
−
f
r
−
l
−
f
r
−
l
+
1
,
d
r
+
2
←
d
r
+
2
−
f
r
−
l
+
1
d_l \leftarrow d_l+f_1,d_{r+1} \leftarrow d_{r+1}-f_{r-l}-f_{r-l+1},d_{r+2} \leftarrow d_{r+2}-f_{r-l+1}
dl←dl+f1,dr+1←dr+1−fr−l−fr−l+1,dr+2←dr+2−fr−l+1
显然差分数组
d
d
d 中元素全为
0
0
0 等价于
a
a
a 与
b
b
b 相等。
所以对于每次操作
O
(
1
)
O(1)
O(1) 修改
d
d
d 数组,用计数器统计
0
0
0 元素的个数即可。
代码
#include<bits/stdc++.h>
#define int long long
const int MAXN = 3e5 + 5;
using namespace std;
int a[MAXN] , cf[MAXN] , n , q , MOD , l , r , f[MAXN] , tmp;
char opt;
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr) , cout.tie(nullptr);
cin >> n >> q >> MOD;
f[1] = f[2] = 1;
for (int i = 1 ; i <= n ; i ++) {
cin >> a[i];
if (i >= 3) f[i] = (f[i - 1] + f[i - 2]) % MOD;
}
for (int i = 1 , x ; i <= n ; i ++) cin >> x , a[i] -= x;
for (int i = 1 ; i <= n ; i ++) {
cf[i] = a[i] - a[i - 1] - a[i - 2];
cf[i] = (cf[i] + MOD) % MOD;
tmp += (cf[i] == 0);
}
while(q --) {
cin >> opt >> l >> r;
int pre = (cf[l] == 0) + (cf[r + 1] == 0 && r < n) + (cf[r + 2] == 0 && r < n - 1);
if (opt == 'A') {
cf[l] = (cf[l] + 1) % MOD , cf[r + 1] = (cf[r + 1] - f[r - l] - f[r - l + 1]) , cf[r + 2] = (cf[r + 2] - f[r - l + 1]);
cf[r + 1] = (cf[r + 1] % MOD + MOD) % MOD , cf[r + 2] = (cf[r + 2] % MOD + MOD) % MOD;
} else {
cf[l] = (cf[l] - 1) % MOD , cf[r + 1] = (cf[r + 1] + f[r - l] + f[r - l + 1]) , cf[r + 2] = (cf[r + 2] + f[r - l + 1]);
cf[l] = (cf[l] + MOD) % MOD , cf[r + 1] = cf[r + 1] % MOD , cf[r + 2] = cf[r + 2] % MOD;
}
int lst = (cf[l] == 0) + (cf[r + 1] == 0 && r < n) + (cf[r + 2] == 0 && r < n - 1);
tmp += (lst - pre);
if (tmp ^ n) puts("NO");
else puts("YES");
}
return 0;
}