D. Three Sequences
-
题意:给一个长度为 n n n 的数组 a a a ,构造两个相同长度的数组 b b b, c c c 。
要求: b [ i ] + c [ i ] = a [ i ] b[ i ] + c[ i ] = a[ i ] b[i]+c[i]=a[i],并且数组 b b b 单调不减,数组 c c c 单调不增。让我们最小化 m a x ( b [ n ] , c [ 1 ] ) max(b[ n ], c[ 1 ]) max(b[n],c[1]),并且输出。
除了初始数组,会有 q q q 次区间加操作,对于每次更新完的数组 a a a,同样要输出 m a x ( b [ n ] , c [ 1 ] ) max(b[ n ], c[ 1 ]) max(b[n],c[1])的最小值。 -
思路: b [ i ] + c [ i ] = a [ i ] b[ i ] + c[ i ] = a[ i ] b[i]+c[i]=a[i], b [ i − 1 ] + c [ i − 1 ] = a [ i − 1 ] b[ i - 1 ] + c[ i - 1 ] = a[ i - 1 ] b[i−1]+c[i−1]=a[i−1] ⇒ \Rightarrow ⇒ b [ i ] − b [ i − 1 ] + c [ i ] − c [ i − 1 ] = a [ i ] − a [ i − 1 ] b[ i ] - b[ i - 1] + c[ i ] - c[ i - 1] = a[ i ] - a[ i - 1] b[i]−b[i−1]+c[i]−c[i−1]=a[i]−a[i−1]
因为数组 b b b 单调不减,所以当 a [ i ] − a [ i − 1 ] > = 0 a[ i ] - a[ i - 1] >= 0 a[i]−a[i−1]>=0 时,令 c [ i ] = c [ i − 1 ] c[ i ] = c[ i - 1] c[i]=c[i−1] 且 b [ i ] = b [ i − 1 ] + a [ i ] − a [ i − 1 ] b[ i ] = b[ i - 1] + a[ i ] - a[ i - 1] b[i]=b[i−1]+a[i]−a[i−1]
因为数组 c c c 单调不增,所以当 a [ i ] − a [ i − 1 ] < 0 a[ i ] - a[ i - 1] < 0 a[i]−a[i−1]<0 时,令 b [ i ] = b [ i − 1 ] b[ i ] = b[ i - 1] b[i]=b[i−1] 且 c [ i ] = c [ i − 1 ] + a [ i ] − a [ i − 1 ] c[ i ] = c[ i - 1] + a[ i ] - a[ i - 1] c[i]=c[i−1]+a[i]−a[i−1]
所以假设 c [ 1 ] = x c[ 1 ] = x c[1]=x,那么 b [ 1 ] = a [ 1 ] − x b[ 1 ] = a[ 1 ] - x b[1]=a[1]−x。
k = ∑ i = 2 n m a x ( 0 , a [ i ] − a [ i − 1 ] ) k = \displaystyle \sum^{n}_{i = 2}{max(0, a[ i ] - a[i - 1])} k=i=2∑nmax(0,a[i]−a[i−1])
由上述的构造我们可以得到 b [ n ] = b [ 1 ] + k = a [ 1 ] − x + k b[ n ] = b[ 1 ] + k = a[ 1 ] - x + k b[n]=b[1]+k=a[1]−x+k
所以我们要最小化 m a x ( b [ n ] , c [ 1 ] ) max(b[ n ], c[ 1 ]) max(b[n],c[1]) 也即最小化 m a x ( a [ 1 ] − x + k , x ) max(a[ 1 ] - x + k, x) max(a[1]−x+k,x)
显然,当 a [ 1 ] − x + k = = x a[ 1 ] - x + k == x a[1]−x+k==x 时,即 x = a [ 1 ] + k 2 x = \displaystyle\frac{a[ 1 ] + k}{2} x=2a[1]+k 时,最大值最小。
关于区间加的操作,这里因为只关心 k k k 值的变化和 a [ 1 ] a[ 1 ] a[1] 值的变化,所以开一个数组 d i f [ i ] = a [ i ] − a [ i − 1 ] dif[ i ] = a[ i ] - a[ i - 1] dif[i]=a[i]−a[i−1], 我们利用差分的思想,区间 [ l , r ] [l, r] [l,r] 操作只更新差值 d i f [ l ] dif[ l ] dif[l] 和 d i f [ r + 1 ] dif[r + 1] dif[r+1]即可。
但是需要注意的是 d i f [ 1 ] dif[1] dif[1] 影响 a [ 1 ] a[1] a[1] 的更新,而 d i f [ 1 ] dif[1] dif[1] 和 d i f [ n + 1 ] dif[n + 1] dif[n+1] 都不影响 k k k 的更新。
然后 O ( n + q ) O(n + q) O(n+q) 即可解决。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define INF 0x3f3f3f3f
#define lowbit(x) x & (-x)
using namespace std;
typedef long long ll;
const int maxN = 100005;
ll read() {
ll x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {
if(ch == '-') f = -f; ch = getchar(); }
while(ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
ll n, a[maxN]; //n->数组长度[1, n]
ll dif[maxN], k;
void solve(){
a[1] += dif[1], dif[1] = 0;
ll c1 = (a[1] + k) >> 1;
ll bn = a[1] - c1 + k;
cout << max(c1, bn) << endl;
}
void update(int pos, ll &x, ll val) {
if(pos > n) return;
if(x > 0) {
k -= x;
}
x += val;
if(pos <= 1) return;
if(x > 0) {
k += x;
}
}
int main()
{
n = read();
for(int i = 1; i <= n; ++ i ) {
a[i] = read();
dif[i] = a[i] - a[i - 1];
}
dif[1] = 0;
k = 0;
for(int i = 2; i <= n; ++ i ) {
k += dif[i] > 0 ? dif[i] : 0;
}
solve();
ll q; q = read();
while(q -- ) {
int l, r; ll val;
cin >> l >> r;
val = read();
update(l, dif[l], val);
update(r + 1, dif[r + 1], -val);
solve();
}
return 0;
}