AcWing 100. IncDec序列
题目链接:100. 增减序列 - AcWing题库
思路
1.首先通过差分构造差分数组,要保证所有数都相同,就要确保差分数组从下标2到n的所有数组值等于0
2.通过贪心,选取差分数组中的两个数(事情上是选取了原数组一个范围大于1的区间,注意是区间,不是单独的数),一个+1,另一个-1,+1在前为曾1,-1在前为-1,
贪心理由:因为对一个区间做修改,最多对差分数组修改两个数(加1或者减1),确保每次操作都尽量修改两个数,就可以使修改次数最少
通过贪心修改差分数组的值后,此时数组有三种情况:
(1)全为0,结束
(2)还有数组值为正值
(3)还有数组值为负值
3.对于(2)(3)两种情况,只能单独增加1或者减去1,假设该差分数组值不为0的下标为k,事实上可以理解为两种特殊情况:(1)一个数字单独加1减1,相当于对数组添加一个元素,下标为n+1,对于区间[k,n+1]加1或者减1,而实际上n+1是不存在的,所以相当与只是单独对该元素加1或者减1,不影响结果;(2)对于第一个元素做修改(注意只要修改第一个元素,那么就会产生不同的解了),修改第一个元素对差分数组无影响,因为差分数组是从下标2开始的,那么就是区间[1,k]减1或者加1
4.(1)由2.3可以得出,一共需要操作的次数等于所有正数的和与负数的和的最大值。
(2)由3可以得出,对剩下的差分数组值求和取绝对值,该值就是可以修改第一个元素的所有次数(即在最小修改次数下不同解的个数),但要注意的是还有+1,因为当差分数组全为0时本身就有一组解,不要忽略掉。
AC代码
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<stdlib.h>
#define maxn 100007
#define ll long long
using namespace std;
ll a[maxn],f[maxn];
int main()
{
ll sum1 = 0,sum2 = 0;
int n;
cin >> n;
for(int i=1;i<=n;i++)
{
cin >> a[i];
f[i] = a[i] - a[i-1];
}
// for(int i=1;i<=n;i++)
// cout << a[i] << " ";
//
// cout << endl << endl;
//
// for(int i=1;i<=n;i++)
// cout << f[i] << " ";
// cout << endl;
for(int i=2;i<=n;i++)
{
if(f[i] > 0)
sum1+= f[i];
if(f[i] < 0)
sum2+= abs(f[i]); //sum2-= f[i]更简洁
}
cout << max(sum1,sum2) << endl;
cout << abs(sum1-sum2) + 1 << endl;
return 0;
}
/*
任选两个数的方法可分为四类
1、2 <= i , j <=n(优先)
2、i = 1, 2 <=j <=n
3、2 <= i <= n , j = n + 1
4、i = 1, j = n + 1(没有意义)
*/
//4 4 4 3
//4 0 0 -1
//sum2 =1
//ans1:4 0 0 0
//ans2:3 0 0 0
//
//4 4 4 2
//4 0 0 -2
//sum2 = 3
//ans1:2 0 0 0
//ans2:4 0 0 0
//ans3:3 0 0 0
//
//4 4 4 2 1
//4 0 0 -2 -1
//sum2 = 4
//ans1: 1 0 0 0 0
//ans2: 4 0 0 0 0
//ans3: 5 0 0 0 0
//