(学习笔记3)差分数组

引例:数列游戏(NKOJ3754)

给定一个长度为N的序列,首先进行A次操作,每次操作在Li和Ri这个区间加上一个数Ci。
然后有B次询问,每次询问Li到Ri的区间和。
初始序列都为0。

第一行三个整数N A B。(1<=N<=1000000,1<=A<=N,A<=B<=N)
接下来A行,每行三个数Li Ri Ci。(1<=Li<=N,Li<=Ri<=N,|Ci|<=100000000000000)。
接下来B行,每行两个数 Li Ri。范围同上。

对于每次询问,输出一行一个整数。
因为最后的结果可能很大,请对结果mod 1000000007。

很显然这道题用暴力要超时,光是修改操作就以O(n^2)。

这其实是一道线段树裸题,但我们可以用更简单的方法。

差分数组(差分序列)

对于一个数组A[i],其差分数组D[i]=A[i]-A[i-1](i>0)且D[0]=A[0]

令SumD[i]=D[0]+D[1]+D[2]+...+D[i] (SumD[]是差分数组D[]的前缀和)

则SumD[i]=A[0]+A[1]-A[0]+A[2]-A[1]+A[3]-A[2]+...+A[i]-A[i-1]=A[i]。

即A[i]的差分数组是D[i],而SumD[i]是A[i]。

对于刚才这道题:
如果每次修改都修改从L到R的值得话,一定会TLE。

注意特殊处:这道题是先进行整体区间修改,最后才统一查询。

所以,我们只需要维护一个差分数组。

对于将区间[L,R]加C,我们只需要将D[L]+C,D[R+1]-C。

附上代码:

#include<stdio.h>
using namespace std;
typedef long long ll;
const int N=2000005;
const ll mod=1000000007;
ll n,a,b;
ll D[N],SumA[N],SumD[N];
int main(){
    scanf("%lld%lld%lld",&n,&a,&b);
    for(int i=1;i<=a;i++){
        ll l,r,c;
        scanf("%lld%lld%lld",&l,&r,&c);
        D[l]=D[l]+c;
        D[r+1]=D[r+1]-c;
    }
    for(int i=1;i<=n;i++)
        SumD[i]=(D[i]+SumD[i-1]);
    for(int i=1;i<=n;i++)
        SumA[i]=(SumA[i-1]+SumD[i]);
    for(int i=1;i<=b;i++){
        ll l,r;
        scanf("%lld%lld",&l,&r);
        printf("%lld\n",(SumA[r]%mod-SumA[l-1]%mod+mod)%mod);    
    }
    return 0;    
}

数列操作(NKOJ3786)

问题描述
给定一个长度为n的数列{a1,a2...an},每次可以选择一个区间[l,r],使这个区间内的数都加一或者都减一。
问至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列有多少种。

输入格式
第一行一个正整数n 
接下来n行,每行一个整数,第i+1行的整数表示ai。


输出格式
第一行输出最少操作次数
第二行输出最终能得到多少种结果

代码

#include<stdio.h>
#include<algorithm>
using namespace std;
const int N=100005;
long long n,a[N],Sum1,Sum2,D[N];
int main(){
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    for(int i=n;i>1;i--){
        D[i]=a[i]-a[i-1];
        if(D[i]>0)
            Sum1+=D[i];
        else
            Sum2+=abs(D[i]);
    }
    printf("%lld\n",max(abs(Sum1),abs(Sum2)));
    printf("%lld",abs(Sum1-Sum2)+1);
    return 0;    
}
全部评论

相关推荐

03-16 11:19
已编辑
门头沟学院 Java
已经一年没发牛客了,为什么呢,因为没脸发...&nbsp;一年前的我自认为在25届中技术一流,八股无敌,项目出色,但是一年校招的蹉跎让我差点转行。24年春招收割了十几个实习&nbsp;offer&nbsp;之后我去了某家大厂实习到9月份转正失败,那时候的我还没有意识到噩梦将来,7月因为投秋招提前批没反馈,于是开始投了几个实习转正岗位练手又拿了3个中大厂&nbsp;offer,这时的我沉浸在我自以为是的骄傲里。9月秋招正式批开始后我几乎把我能找到的所有的岗位都投了一遍,只收获了大厂海笔,0面试。10月份第一家给我面试的公司是数字马力(蚂蚁的内包),诚恳的说,当时收到这家面试是嚣张的,觉得我拿这个&nbsp;offer&nbsp;如探囊取物,就当个保底吧。...
中街牛奶提子:是啊,不应该在秋招的时候继续投实习岗。也劝26届的,八月末后,实习岗就不应该投,给人错误的行情认知。佬是学院本,觉得约面难,双非何尝不是一样呢,秋招战场的激烈和实习完全不同。当时我秋招的时候也是边面实习,当时面实习面一个过一个觉得自己很优越,觉得能收获一堆实习offer那秋招肯定也行。为什么要在秋招拿一堆实习offer增强自己所谓的虚荣心,当时就是贱,为了所谓的攀比虚荣心
点赞 评论 收藏
分享
程序员鼠鼠_春招版:都很烂大街,rpc也基本没人问,考研吧,不然就包装一段实习再去
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务