Codeforces Round #816 (Div. 2) C. Monoblock

本文介绍了一种解决计算机科学中的数组处理问题的方法,具体涉及数组的神奇值计算。在每次单点修改数组后,需要计算所有子段的神奇值之和。通过观察数组并维护特殊贡献值,可以高效地更新总和。提供的C++代码展示了如何实现这一过程。
摘要由CSDN通过智能技术生成

 

翻译:

 

Stanley决定购买一台由monblock公司生产的新的台式电脑,为了解决他们网站上的验证码问题,他需要解决以下任务。

数组的神奇之处在于数组可以被分割的连续相同数字块的最小数量。例如,数组的强大

[1,1,1]为1;
[5,7]为2,可分为[5]和[7]块;
[1、7、7、7、7、7、7、7、9,9日,9日,9日,9日,9日,9日9,9]是3,因为它可以分成块[1],[7、7、7、7、7、7、7],和[9 9 9,9日,9日,9日,9日9,9]。
给出一个长度为𝑛的数组𝑎。对两个整数𝑖、𝑥有𝑚查询。查询𝑖,𝑥意味着从现在开始数组𝑎的𝑖-th元素等于𝑥。

在每次查询之后,打印数组𝑎的所有子段之间的awesome值的总和。换句话说,在每个查询之后都需要进行计算
∑𝑙= 1𝑛∑𝑟=𝑙𝑛𝑔(𝑙𝑟),
𝑔(𝑙𝑟)数组的精彩𝑏=[𝑎𝑙,𝑎𝑙+ 1,…,𝑎𝑟]。

输入
第一行给出了两个整数𝑛和𝑚(1≤𝑛,𝑚≤105)。

第二行包含𝑛整数𝑎1𝑎2,…,𝑎𝑛(1≤𝑎𝑖≤109)——𝑎数组。

在接下来的𝑚行中,将给出查询的描述。每行包含两个整数𝑖和𝑥(1≤𝑖≤𝑛,1≤𝑥≤109)。

输出
在新一行打印每个查询的答案。

例子
inputCopy
5个5
1 2 3 4 5
3 - 2
4个2
3个1
2 1
2 - 2
outputCopy
29
23
35
25
35
请注意
在第一个查询𝑎等于[1,2,2,4,5]之后,答案是29,因为我们可以按以下方式分割每个子段:

[1;1]:[1], 1块;
[1;2]:[1]+[2], 2块;
[1;3]:[1]+[2,2], 2块;
[1;4]:[1]+[2,2]+[4], 3块;
[1;5]:[1]+[2,2]+[4]+[5], 4块;
[2;2]:[2], 1块;
[2;3]:[2,2], 1块;
[2;4]:[2,2]+[4], 2块;
[2;5]:[2,2]+[4]+[5], 3块;
[3;3]:[2], 1块;
[3;4]:[2]+[4], 2块;
[3;5]:[2]+[4]+[5], 3块;
[4;4]: [4], 1 block;
[4;5]:[4]+[5], 2块;
[5;5]:[5], 1块;
这是1 + 2 + 2 + 3 + 4 + 1 + 1 + 2 + 3 + 1 + 2 + 3 + 1 + 2 + 1 = 29。

题意:根据题意来给的公式不断计算,然后每次单点修改,再次查询。

思路:我们来将数组倒着看,每个相邻不同的对于总贡献是前一个的贡献加上这个数的下标,然后不同的则是前一个的贡献+1,然后可以推出值的改变对总贡献的影响,(i-1)*(n-i+1),然后对于四种情况来进行判断,可能说的不太明白,具体的可以看代码。

代码:

#include <iostream>
#include <algorithm>
#include <string.h>
#include <string>
#include <math.h>
#include <stdio.h>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<tuple>
#include<numeric>
using namespace::std;
typedef long long  ll;
inline __int128 read(){
    __int128 x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if(ch == '-')
            f = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9'){
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
inline void print(__int128 x){
    if(x < 0){
        putchar('-');
        x = -x;
    }
    if(x > 9)
        print(x / 10);
    putchar(x % 10 + '0');
}
int n,m;
ll ss[100005];
ll sr[100005];
ll sum=0;
ll q,w;
int main(){
    ios::sync_with_stdio(false);
    cin.tie(); cout.tie();
    cin>>n>>m;
    int kl=n;
    for (int i = kl; i>=1; i--) {
        cin>>ss[i];
    }
    sr[1]=1;
    for (int i =2; i<=n; i++) {
        if (ss[i]!=ss[i-1]) {
            sr[i]=sr[i-1]+i;
        }
        else{
            sr[i]=sr[i-1]+1;
        }
    }
    for (int i =1; i<=n; i++) {
        sum+=sr[i];
    }
    
    while (m--) {
        cin>>q>>w;
        q=n-q+1;
        if (w==ss[q]) {
            printf("%lld\n",sum);
            continue;
        }
        if (ss[q]==ss[q-1]&&q-1>0) {
            sum+=(q-1)*(n-q+1);
        }
        if (ss[q]==ss[q+1]&&q+1<=n) {
            sum+=q*(n-q);
        }
        if (w==ss[q+1]&&ss[q]!=ss[q+1]&&q+1<=n) {
            sum-=q*(n-q);
        }
        if (w==ss[q-1]&&ss[q]!=ss[q-1]&&q-1>0) {
            sum-=(q-1)*(n-q+1);
        }
        ss[q]=w;
        printf("%lld\n",sum);
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值