戳我进原题
题意: 给定一个长度为
n
n
n的序列
a
a
a,每次可以指定一个区间给这个区间的所有数统一加
1
1
1或减
1
1
1,问最少要操作多少次可以使得序列
a
a
a中的所有数都相同,并且输出最终可能得到的序列个数。
数据范围:
1
≤
n
≤
1
0
5
1\leq n\leq 10^5
1≤n≤105
题解:
区间的简单操作可以想到差分:
那么定义
a
a
a的差分序列为
b
b
b:
如果要使得所有数都相同,则使得
b
[
2
]
,
b
[
3
]
,
.
.
.
,
b
[
n
]
b[2],b[3],...\ ,b[n]
b[2],b[3],... ,b[n]都等于
0
0
0。
对于序列
a
a
a的区间
[
l
,
r
]
[l,r]
[l,r]操作即对差分序列
b
b
b的
b
[
l
]
b[l]
b[l]和
b
[
r
+
1
]
b[r+1]
b[r+1]操作
当
[
l
,
r
]
[l,r]
[l,r]区间加
1
1
1时,相当于
b
[
l
]
=
b
[
l
]
+
1
b[l]=b[l]+1
b[l]=b[l]+1,
b
[
r
+
1
]
=
b
[
r
+
1
]
−
1
b[r+1]=b[r+1]-1
b[r+1]=b[r+1]−1
当
[
l
,
r
]
[l,r]
[l,r]区间减
1
1
1时,相当于
b
[
l
]
=
b
[
l
]
−
1
b[l]=b[l]-1
b[l]=b[l]−1,
b
[
r
+
1
]
=
b
[
r
+
1
]
+
1
b[r+1]=b[r+1]+1
b[r+1]=b[r+1]+1
因为我们需要将所有的
b
[
2
,
.
.
.
,
n
]
b[2,...\ ,n]
b[2,... ,n]都操作为
0
0
0,又因为每次需要使得一个
b
[
l
]
b[l]
b[l]加
1
1
1或减
1
1
1,另一个
b
[
r
+
1
]
b[r+1]
b[r+1]减
1
1
1或加
1
1
1,即
b
[
l
]
b[l]
b[l]和
b
[
r
+
1
]
b[r+1]
b[r+1]进行相反的操作,所以我们尽可能选择一个需要由负变
0
0
0的
b
[
i
]
b[i]
b[i]和一个需要由正变
0
0
0的
b
[
j
]
b[j]
b[j],这样一次操作可以操作两个
b
b
b。
当由负变 0 0 0的 b [ i ] b[i] b[i]和由正变 0 0 0的 b [ j ] b[j] b[j]其中有一个已经没有时,我们之后的操作可以有两个选择,要么选择 b [ 1 ] b[1] b[1],要么选择 b [ n + 1 ] b[n+1] b[n+1],这两者对于最终操作的数量是没有影响的,但是这两者影响的是最少操作数量下会得到不同的序列,即我们可以选择对 b [ 1 ] b[1] b[1]操作 [ 0 , a b s ( p o s , n e g ) ] [0,abs(pos,neg)] [0,abs(pos,neg)]次,故总共是 a b s ( p o s , n e g ) + 1 abs(pos,neg)+1 abs(pos,neg)+1种不同序列。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
ll a[N];
int n;
int main()
{
ll pos = 0, neg = 0;
scanf("%d", &n);
for(int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
for(int i = n; i >= 1; --i) a[i] -= a[i - 1];
for(int i = 2; i <= n; ++i)
if(a[i] > 0) pos += a[i];
else neg -= a[i];
printf("%lld\n%lld\n", max(pos, neg), abs(pos - neg) + 1);
}