代码源:562、蜗蜗的数列

318 阅读5分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路 logo.png

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

题目描述

这是3月19日代码源div1的每日一题。

知识点:差分

蜗蜗的数列 - 题目 - Daimayuan Online Judge

题目描述

蜗蜗有两个长度都为 n 的数列 A,B,同时他会进行 q 次操作。

对于每一次操作,他会先选择其中一个数列 (A/B) ,再选择一个区间 [l,r] (1≤l≤r≤n),将选定的序列 [l,r] 中的数对位加上Fibonacci数列

换句话说,就是将选定数列的第 l 项加上 1,第 l+1 项加上 1,第 l+2 项加上 2,第 l+3 项加上 3… 第 r 项加上 Fib(r−l+1),即 Fibonacci 数列的第 r−l+1 项。

在每次操作结束的时候,蜗蜗都会变得非常好奇。他想知道此时 A 和 B 两个序列是否相同,由于他一看到比较长的数就会头晕,所以你只需要判断 A 和 B 在模 M 的意义下是否相同即可。

输入格式

第一行三个数 n,q,M,分别表示数列的长度,操作的总次数和模数。

第二行和第三行各输入 n 个整数,表示 A 和 B 的初始值。

接下来 q 行每行包含一个字符 c 和两个整数 l,r,描述一次操作。具体细节见样例。

输出格式

输出 q 行,每行一个字符串 YesNo ,表示此时两个数列是否在模 M 的意义下相同。

样例1输入

3 5 3
2 2 1
0 0 0
A 1 3
A 1 3
B 1 1
B 2 2
A 3 3

样例1输出

Yes
No
No
No
Yes

问题分析

看到这种给一个数组中的一段连续加上值后判断值的情况的,一开始想到的是线段树(但是我不会啊www),在想着要不要先去学个线段树再回来写这题时,去cf上看到了用差分的方式做,但这有两个数组怎么差分?。

首先,我们要知道的是a和b是否相等,而我们知道如果a==b,那么a-b=0,我们可以构造一个数组c,c[i]=a[i]-b[i],这样如果c数组内部全是0,就说明a数组和b数组是相等的。当对a数组进行加上斐波那契数列的操作时,就相当于给c数组加上了斐波那契数列;反之对b加上fib,则c是减去fib。这样,我们就可以在c数组上进行操作了。

此时我们就可以用差分的方式来维护c数组的值了,再创建一个数组d。关于d[i]的值的情况,我们要先说明下差分的性质:区间加同一个数可以差分是因为增量序列的递推式为 ai=ai-1,而后一个数减去前一个数正好抵消。

此时我们加上的不是相同的数,而是斐波那契数列怎么办呢?注意,fib的递推式为fib(i)=fib(i-1)+fib(i-2)。那么我们用一个数(位置从三开始)减去它前面的两个数,也是可以正好抵消的,所以我们d数组应该为d[i]=c[i]-c[i-1]-c[i-2]。d[1]=c[1],d[2]=c[2]-c[1]。正常差分是对区间左端点加上值,并给区间右端点+1减去值,所以此时的d数组应该是每次给左端点加上1,右端点+1处减去fib[r-l+2],右端点+2处减去fib[r-l+1]。所以可以看出我们的d区间应该比ab区间的长度多2。

然后我们就处理d区间就可以了,一开始计算1到n位置的数有多少个0(额外扩建的两个位置不用算)。然后每次对数组A[l,r]操作时,d[l]-=1,d[r+1]-=fib[r-l+2],d[r+2]-=fib[r-l+1],如果是B数组则加减要反过来。然后计算下0数字的改变情况,如果0的数量等于n,说明c都是0,说明A和B相等。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")

#define endl '\n';
typedef long long ll;
typedef pair<int, int>PII;
const int N = 1e6 + 50;
ll a[N], b[N], c[N], d[N], fib[N];
ll res = 0, n, m, MOD;

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    cin >> n >> m >> MOD;
    fib[1] = 1, fib[2] = 1;
    for (int i = 3; i <= 1e6+5; i++)fib[i] = (fib[i - 1] + fib[i - 2]) % MOD;
    for (int i = 1; i <= n; i++)cin >> a[i];
    for (int i = 1; i <= n; i++)
    {
        cin >> b[i];
        c[i] = a[i] - b[i];
    }
    d[1] = c[1];
    d[2] = (c[2] - c[1])%MOD;
    for (int i = 1; i <= n + 2; i++)
    {
        if(i>=3)d[i] = (c[i] - c[i - 1] - c[i - 2])%MOD;
        if (i<=n&&d[i] == 0)res++;
    }
    while (m--)
    {
        char st;
        int l, r;
        cin >> st >> l >> r;
        if (st == 'A')
        {
            if (d[l] == 0)res--;
            if (r + 1 <= n && d[r + 1] == 0)res--;
            if (r + 2 <= n && d[r + 2] == 0)res--;
            d[l] = (d[l] + 1) % MOD;
            d[r + 1] = (d[r + 1] - fib[r - l + 2]) % MOD;
            d[r + 2] = (d[r + 2] - fib[r - l + 1]) % MOD;
            if (d[l] == 0)res++;
            if (r + 1 <= n && d[r + 1] == 0)res++;
            if (r + 1 <= n && d[r + 2] == 0)res++;
        }
        else
        {
            if (d[l] == 0)res--;
            if (r+1<=n&&d[r + 1] == 0)res--;
            if (r + 2 <= n && d[r + 2] == 0)res--;
            d[l] = (d[l] - 1) % MOD;
            d[r + 1] = (d[r + 1] + fib[r - l + 2]) % MOD;
            d[r + 2] = (d[r + 2] + fib[r - l + 1]) % MOD;
            if (d[l] == 0)res++;
            if (r + 1 <= n && d[r + 1] == 0)res++;
            if (r + 2 <= n && d[r + 2] == 0)res++;
        }
        if (res == n)
        {
            cout << "Yes" << endl;
        }
        else
        {
            cout << "No" << endl;
        }
    }
    return 0;
}