差分 IncDec序列

一.差分是前缀和的逆过程

有下面两个数组:

a[1]  a[2]  a[3]  a[4] 
  1     3     6    2
b[1]  b[2]  b[3]  b[4]
  1     2     3    -4 
  • 数组 b 是数组 a 的差分序列:
b[1]=a[1]
b[2]=a[2]-a[1]
b[3]=a[3]-a[2]
b[4]=a[4]-a[3]
.
.
.
b[i]=a[i]-a[i-1]
  • 数组 a 是数组 b 的前缀和:
a[1]=b[1]
a[2]=a[1] + a[2]-a[1] = b[1] + b[2]
a[3]=a[1] + a[2]-a[1] + a[3]-a[2] = b[1] + b[2] +b[3]
a[4]=a[1] + a[2]-a[1] + a[3]-a[2] + a[4]-a[3] = b[1] + b[2] +b[3] +b[4]
.
.
.
a[i]=b[1]+b[2]+...+b[i]

二.应用

SDNU_ACM_ICPC_2020_Winter_Practice_2nd J

题目
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个气球总共被涂色的次数。
Sample Input
3
1 1
2 2
3 3
3
1 1
1 2
1 3
0
Sample Output
1 1 1
3 2 1
思路
每次操作是区间 【 l , r 】中的所有数加1

由上面的分析可知,数组 a 是数组 b 的前缀和,
并且在 a [ l ] 及以后(a[ l+1 ] ~ a[ n ]) 的组成中才有b[ l ]

如果b[ l ] 增加一个常数c
那么 a [ l ] ~ a[ n ] 都会增加常数c

同理, 如果b[ r+1] 减去一个常数c
那么 a [ r+1 ] ~ a[ n ] 都会减去常数c

因此,
a [ 1 ] ~ a[ l-1 ] 不变
a [ l ] ~ a [ r ] 加 c
a [ r+1 ] ~ a[ n ]不变
这样就做到了 【 l , r 】中的所有数加c

代码

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<string.h>
#include<vector>
#include<cmath>
#include <queue>
using namespace std;
typedef long long ll;

const int M = (int)1e5;
 
int p[M + 5];
 
int main()
{
    int n;
    while(~scanf("%d", &n) && n)
    {
        for(int i = 1; i <= n; ++i)
            p[i] = 0;
        int l, r;
        for(int i = 1; i <= n; ++i)
        {
            scanf("%d %d", &l, &r);
            p[l]++;
            p[r + 1]--;
        }
        int cnt = 0;
        for(int i = 1; i <= n; ++i)
        {
            cnt += p[i];///a[i]=b[1]+b[2]+...+b[i]
            printf("%d%c", cnt, i == n ? '\n' : ' ');
        }
    }
    return 0;
}


IncDec序列–ACWing题库
题目
给定一个长度为 n 的数列 a1,a2,…,an,每次可以选择一个区间 [l,r],使下标在这个区间内的数都加一或者都减一。

求至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列可能有多少种。

输入格式
第一行输入正整数n。

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

输出格式
第一行输出最少操作次数。

第二行输出最终能得到多少种结果。

数据范围
0<n≤105,
0≤ai<2147483648
输入样例:
4
1
1
2
2
输出样例:
1
2
思路
1. 使数列中的所有数都一样

即 a[1]=a[2]=a[3]=…=a[n]
即 b[1]=a[1] , b[2]=b[3]=b[4]=…=0

2. 对差分数组b的操作就是 在2~n中选数 +1 或着 - 1 使得他们最后都等于0
有三种操作:

  1. l >=2,r<=n
    即对b数组中的两个数,一个+1,一个-1
            b[l]++;
            b[r + 1]--;
            //即对a数组区间  l ~ r  中的数+1或 -1
  1. l =1,2<= r <= n
    改动b数组一个数
    //即对a数组 前缀 +1或 -1
  2. 2<= l <=n,l =n+1
    改动b数组一个数
    //即对a数组 后缀 +1或 -1

3. 要想操作最少,就要尽可能的选择第一种操作(即对b数组中的两个数,一个+1,一个-1)。
那么就要从b数组中选择一个正数,一个负数

所以操作次数就是,| 正数和-负数和 | + min(正数和,负数和)

4. 第一种操作是固定的,那么方案的不同由第2、3种操作每一种的操作次数决定

2、3种的操作总次数为 | 正数和-负数和 |
方案数位 | 正数和-负数和 | +1

代码

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<string.h>
#include<vector>
#include<cmath>
#include <queue>
using namespace std;
typedef long long ll;

const int M = (int)1e5;

int a[M + 5];

int main()
{
    int n;
    cin>>n;
    a[0]=0;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=n;i>=1;i--)a[i]-=a[i-1];///n~1
    ll z=0,f=0;
    for(int i=2;i<=n;i++)
    {
        if(a[i]>0)z+=a[i];
        else f-=a[i];
    }
    ll ans=0;
    ans=abs(z-f)+min(z,f);
    cout<<ans<<endl<<abs(z-f)+1<<endl;
    return 0;
}


POJ 3263
题目
FJ’s N (1 ≤ N ≤ 10,000) cows conveniently indexed 1…N are standing in a line. Each cow has a positive integer height (which is a bit of secret). You are told only the height H (1 ≤ H ≤ 1,000,000) of the tallest cow along with the index I of that cow.

FJ has made a list of R (0 ≤ R ≤ 10,000) lines of the form “cow 17 sees cow 34”. This means that cow 34 is at least as tall as cow 17, and that every cow between 17 and 34 has a height that is strictly smaller than that of cow 17.

For each cow from 1…N, determine its maximum possible height, such that all of the information given is still correct. It is guaranteed that it is possible to satisfy all the constraints.

Input
Line 1: Four space-separated integers: N, I, H and R
Lines 2… R+1: Two distinct space-separated integers A and B (1 ≤ A, B ≤ N), indicating that cow A can see cow B.
Output
Lines 1… N: Line i contains the maximum possible height of cow i.
Sample Input
9 3 5 5
1 3
5 3
4 3
3 7
9 8
Sample Output
5
4
5
3
4
4
5
5
5

思路
假设所有牛都和最高牛一样高,那么差分序列f中
f[ 1 ] = 5, f[ 2 ] ~ f[ n ]=0

已知a牛能看到b牛,那么a最高和b等高,a,b之间的牛最高为b的高度 - 1

即 f [a+1]–,f [ b ]++;

注意!!!
数据可能 a>b
所以要用到swap

数据可能重复
那么就要用到map<pair<ll,ll>,int>s 来存所有的a b

代码

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<string.h>
#include<vector>
#include<cmath>
#include <map>
using namespace std;
typedef long long ll;
ll f[10007]={0};
map<pair<ll,ll>,int>s;
int main()
{
    ll n,ans=0,l,h,r,a,b;
    cin>>n>>l>>h>>r;
    for(ll i=1;i<=r;i++)
    {
        scanf("%lld%lld",&a,&b);
        if(a>b)swap(a,b);
        if(!s[make_pair(a,b)]){f[a+1]--;f[b]++;}
        s[make_pair(a,b)]=1;
    }
    f[1]=h;
    for(ll i=1;i<=n;i++)
    {
        ans+=f[i];
        printf("%lld\n",ans);
    }
    return 0;
}

发布了46 篇原创文章 · 获赞 0 · 访问量 1144

猜你喜欢

转载自blog.csdn.net/weixin_45719073/article/details/104279894