• 差分数组理解及题目


    1.定义:

    对于已知有n个元素的离线数列d,我们可以建立记录它每项与前一项差值的差分数组f:显然,f[1]=d[1]-0=d[1];对于整数i∈[2,n],我们让f[i]=d[i]-d[i-1]。

    2.简单性质:

    (1)计算数列各项的值:观察d[2]=f[1]+f[2]=d[1]+d[2]-d[1]=d[2]可知,数列第i项的值是可以用差分数组的前i项的和计算的,即d[i]=f[i]的前缀和。
    (2)计算数列每一项的前缀和:第i项的前缀和即为数列前i项的和,那么推导可知

    即可用差分数组求出数列前缀和;

    3.用途:

    (1)快速处理区间加减操作:

    假如现在对数列中区间[L,R]上的数加上x,我们通过性质(1)知道,第一个受影响的差分数组中的元素为f[L],即令f[L]+=x,那么后面数列元素在计算过程中都会加上x;最后一个受影响的差分数组中的元素为f[R],所以令f[R+1]-=x,即可保证不会影响到R以后数列元素的计算。这样我们不必对区间内每一个数进行处理,只需处理两个差分后的数即可;

    (2)询问区间和问题:

    由性质(2)我们可以计算出数列各项的前缀和数组sum各项的值;那么显然,区间[L,R]的和即为ans=sum[R]-sum[L-1];

    注意:差分数组适用于离线的区间修改问题,如果是在线的话应该用线段树或其他数据结构。

    注意:离线区间修改是指,将所有修改操作全部读入,然后一起处理。 而在线是指,每读入一个修改操作,就执行一次修改。

    题目

    1.[HDU1556]Color the ball

    Description

    -N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的“小飞鸽"牌电动车从气球a开始到气球b依次给每个气球涂一次颜色。但是N次以后lele已经忘记了第I个气球已经涂过几次颜色了,你能帮他算出每个气球被涂过几次颜色吗?
    -Input:每个测试实例第一行为一个整数N,(N <= 100000).接下来的N行,每行包括2个整数a b(1 <= a <= b <= N)。当N = 0,输入结束。
    -Output:每个测试实例输出一行,包括N个整数,第I个数代表第I个气球总共被涂色的次数。

    Solution

    1.记录各次操作,对差分数组进行对应修改,改变量为1(用途1);
    2.使用性质(1)计算各项的值即可;

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    using namespace std; 
    int d[100010],a[100010],l,r;
    int main(){
    	int n;
    	while(scanf("%d",&n),n)
    	{
    		memset(d,0,sizeof(d));
    		memset(a,0,sizeof(a));
    		for(int i=1;i<=n;++i){
    			scanf("%d%d",&l,&r);
    			d[l]+=1;
    			d[r+1]-=1;
    		}
    		for(int i=1;i<=n;++i) a[i]=a[i-1]+d[i];
    		for(int i=1;i<n;++i) printf("%d ",a[i]);
    		printf("%d
    ",a[n]);
    	}
    	return 0;
    }
    

      2.牛客“科大讯飞杯”第十七届同济大学程序设计预选赛暨高校网络友谊赛F题

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int maxn = 2e5 + 5;
    ll b[maxn];
    ll a[maxn];
    int main(){
        int n,m;
        scanf("%d%d",&n,&m);
        int l,r;
        for(int i = 1;i <= m;i++){
            scanf("%d%d",&l,&r);
            b[l]++;
            b[r+1]--;
        }
        for(int i = 1;i <= n;i++)
            a[i] = a[i - 1] + b[i];
        sort(a + 1,a + 1 + n);
        ll ans = 0;
        for(int i = n;i > 0;i--) {
            ans += i * a[i];
            if(a[i] == 0) {
                break;
            }
        }
        printf("%lld
    ",ans);
        return 0;
    }
    

      

  • 相关阅读:
    对中级 Linux 用户有用的 20 个命令
    对 Linux 新手有用的 20 个命令
    有趣的JavaScript原生数组函数
    编写更好的CSS
    一套名企WEB前端面试题,不提供答案
    探索JavaScript中Null和Undefined的深渊
    30个你必须记住的CSS选择符
    揭秘JavaScript中谜一样的this
    2013年JavaScript开发人员调查结果
    给HTML初学者的三十条最佳实践
  • 原文地址:https://www.cnblogs.com/clb123/p/12865045.html
Copyright © 2020-2023  润新知