AcWing - 100 - 增减序列(差分)

题目链接
  首先我们要知道差分数组的第一个元素等于原数组的第一个数,而其他的数等于他和他前一个数的差,那么如果一个数列中的所有数都相等,那么他的差分数列除了第一个数外,别的数肯定都是0。那么我们现在有一个差分数组\(B\),我们要让区间\([l, r]\)中所有数加\(1\)或者减\(1\)可能有一下情况:
  1.  \(2\leq l \leq n\)\(l \leq r \leq n-1\)
  2.  \(1\leq l \leq n\)\(l \leq r \leq n-1\)
  3.  \(2\leq l \leq n\)\(l \leq r \leq n\)
  4.  \(1\leq l \leq n\)\(l \leq r \leq n\)
  我们的目标是使差分数组除了第一个数以外的所有数变为\(0\),所以我们进行操作1.时,可以同时改变\(b1\)之外的两个数。我们进行操作2.时,可以改变\(b1\)\(b1\)之外的另一个数。进行操作3.时可以改变\(b1\)之外的1个数以及\(b{n+1}\)但是\(b{n+1}\)对于我们来说并没有用,相当于只改变了一个数。而操作4.除了改变\(b1\)之外对差分数组没有什么有效的贡献了,只会增加操作次数,所以我们不用考虑。那么我们要用最小的次数来修改这个数组使他的全部数字都变成一个数就要尽量的使用操作1.然后再考虑2和3,我们操作1进行的最多的次数就是差分数组除1之外的所有正数与负数的绝对值的差的绝对值,而剩下的那部分就要用操作2和操作3。我们前面已经知道了,在一个所有数都相等的差分数组里面除了\(b1\)其他的数都是0,所以我们操作之后得到的数列有多少种就取决于\(b1\)有多少种,而我们只有操作2和3会改变\(b1\),所以答案就是前面所得差的绝对值再加上\(1\)(最少使用0次操作2,最多使用的次数等于差的绝对值)。

//https://www.cnblogs.com/shuitiangong/
#include<set>
#include<map>
#include<list>
#include<stack>
#include<queue>
#include<cmath>
#include<cstdio>
#include<cctype>
#include<string>
#include<vector>
#include<climits>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define endl '\n'
#define rtl rt<<1
#define rtr rt<<1|1
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define maxx(a, b) (a > b ? a : b)
#define minn(a, b) (a < b ? a : b)
#define zero(a) memset(a, 0, sizeof(a))
#define INF(a) memset(a, 0x3f, sizeof(a))
#define IOS ios::sync_with_stdio(false)
#define _test printf("==================================================\n")
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
typedef pair<ll, ll> P2;
const double pi = acos(-1.0);
const double eps = 1e-7;
const ll MOD =  9901;
const int INF = 0x3f3f3f3f;
const int _NAN = -0x3f3f3f3f;
const double EULC = 0.5772156649015328;
const int NIL = -1;
template<typename T> void read(T &x){
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
const int maxn = 1e5+10;
int arr[maxn];
int main(void) {
    int n;
    while(~scanf("%d", &n)) {
        for (int i = 1; i<=n; ++i) 
            scanf("%d", &arr[i]);
        ll sump = 0, sumn = 0;
        for (int i = n; i>=1; --i) {
            arr[i] -= arr[i-1];
            if (arr[i]>0 && i != 1) sump += arr[i];
            else if (i!=1) sumn += arr[i];
        }
        printf("%lld\n%lld\n", abs(-sumn-sump)+min(sump, -sumn), abs(-sumn-sump)+1);
    }
    return 0;
}
posted @ 2020-03-22 11:36  shuitiangong  阅读(263)  评论(0编辑  收藏  举报