Problem E
分类讨论
题意
给你一个 n n n 个元素的数组 A ( 1 ≤ a i ≤ 1 e 6 ) A(1\leq a_i\leq 1e6) A(1≤ai≤1e6),每次操作可以 ∀ i ∈ [ 1 , n ] \forall i\in [1,n] ∀i∈[1,n],将 a i a_i ai 减少2, a i − 1 , a i + 1 a_{i-1},a_{i+1} ai−1,ai+1 各减少1,问最少多少次操作可以使数组中至少两项小于等于0。
思路
观察容易发现,我们进行操作位置至多只有两个,相对应的,设最终小于等于0的两项下标分别为
i
,
j
i,j
i,j。
则
i
,
j
i,j
i,j 一定满足以下3种条件之一:
- i , j i,j i,j 相邻,如 [ 1000 , 3 , 3 , 1000 ] [1000,3,3,1000] [1000,3,3,1000]。
- i , j i,j i,j 间隔为1,如 [ 5 , 100 , 3 ] [5,100,3] [5,100,3] [ 4 , 100 , 4 ] [4,100,4] [4,100,4]
- i , j i,j i,j 间隔大于1,如 [ 3 , 100 , 100 , 3 ] [3,100,100,3] [3,100,100,3]
先考虑第三种情况,
i
,
j
i,j
i,j 独立,答案就是
(
a
i
+
1
)
/
2
+
(
a
j
+
1
)
/
2
(a_i+1)/2+(a_j+1)/2
(ai+1)/2+(aj+1)/2。
对第二种情况,注意到如果
a
i
,
a
i
+
2
a_i,a_{i+2}
ai,ai+2 不全为奇数,那么可以采用第三种方法,否则可以先对
i
+
1
i+1
i+1 进行一次操作将
a
i
,
a
i
+
2
a_i,a_{i+2}
ai,ai+2 变为偶数再进行操作3,答案会少1。
最后考虑第一种情况,假设
a
i
≥
a
j
a_i\geq a_j
ai≥aj,若
a
i
≥
2
a
j
a_i \geq 2a_j
ai≥2aj ,则答案显然为
(
a
i
+
1
)
/
2
(a_i+1)/2
(ai+1)/2,否则答案为
(
a
i
+
a
j
+
2
)
/
3
(a_i+a_j+2)/3
(ai+aj+2)/3 。
对第一种情况的简单证明:
- a i ≥ 2 a j a_i \geq 2a_j ai≥2aj 显然仅对 i i i 操作,次数为 ( a i + 1 ) / 2 (a_i+1)/2 (ai+1)/2
- 因为一定可以通过若干次操作使得 a i ′ = a j ′ a_i' = a_j' ai′=aj′。接下来对于两个相等的数,在操作的过程中, ∣ a i − a j ∣ ≤ 1 |a_i-a_j|\leq 1 ∣ai−aj∣≤1 恒成立,所以一定会转移到(1,0)(0,1)(0,0)(1,1)四种中的一种,其实对应的就是(a+b)%3的值,因为每次减3所以如果(a+b)%3=2 最后就会转移到(1,1)…不管是哪种,转移到这四种的次数都是 ( a + b ) / 3 (a+b)/3 (a+b)/3 向下取整,而对于 (a+b)%3 != 0 的情况还需要再+1,所以最终答案就是 ( a + b + 2 ) / 3 (a+b+2)/3 (a+b+2)/3。
代码
int a[maxn];
void solve() {
int n;
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
int ans = INF;
a[n+1] = a[0] = INF;
for(int i = 1; i <= n; i++) {
int q = max(a[i], a[i+1]);
int p = min(a[i], a[i+1]);
int tmp = 0;
if(q >= 2*p) {
tmp = (q+1) >> 1;
}
else {
tmp = (p + q + 2) / 3;
}
ans = min(ans, tmp);
if((a[i-1]&1) && (a[i+1] & 1)) {
ans = min(ans, a[i-1]/2+a[i+1]/2+1);
}
}
sort(a + 1, a + n + 1);
ans = min(ans,(a[1]+1)/2 + (a[2]+1)/2);
cout << ans << endl;
}