「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[li+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 1n,q3×1051MOD109+7

思路

难度 2700,很好的一道差分题。

考虑转化题意,不妨令 c i = a i − b i c_i = a_i-b_i ci=aibi,则当且仅当 ∀ 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=fi1+fi2,因此,很自然地想到通过差分抵消中间项,形式化定义如下:

d i = c i − c i − 1 − c i − 2 d_i=c_i-c_{i-1}-c_{i-2} di=cici1ci2

那么,每次操作就等价于:
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} dldl+f1dr+1dr+1frlfrl+1dr+2dr+2frl+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;
}

posted @ 2024-04-05 23:57  Fracture_Dream  阅读(3)  评论(0编辑  收藏  举报  来源