题意:给定长度为 n n n 的数组 a a a,求将数组中任意的两个值减小到 0 0 0 的最小操作次数。每次操作可以选择一个 1 ≤ i ≤ n 1 \leq i \leq n 1≤i≤n ,使得, a [ i ] = a [ i ] − 2 , a [ i − 1 ] = a [ i − 1 ] − 1 , a [ i + 1 ] = a [ i + 1 ] − 1 a[i] = a[i] - 2,a[i-1] = a[i-1] - 1,a[i+1] = a[i+1] - 1 a[i]=a[i]−2,a[i−1]=a[i−1]−1,a[i+1]=a[i+1]−1 。 1 ≤ a i ≤ 1 0 6 1 \leq a_i \leq 10^6 1≤ai≤106
思路:由题意可得,需要选择两个值,将其值变为 0 0 0 ,每一次操作至少会改变两个值,所以存在以下的几种情况:
- 选择的两个值间隔大于 2 2 2 , ( ∣ i − j ∣ > 2 ) (|i - j| > 2) (∣i−j∣>2)
- 选择的两个值间隔等于 2 2 2 ,两者之间不能相互影响, ( ∣ i − j ∣ = 2 ) (|i - j| = 2) (∣i−j∣=2)
- 选择的两个值间隔小于 2 2 2 ,两者之间能相互影响, ( ∣ i − j ∣ < 2 ) (|i - j| < 2) (∣i−j∣<2)
对于第一种情况,只需找出数组 a a a 中的最小的两个值 a i a_i ai 、 a j a_j aj ,计算出将这两个值变为 0 0 0 的最小操作 ⌈ a i / 2 ⌉ + ⌈ a j / 2 ⌉ \lceil a_i/2 \rceil + \lceil a_j/2 \rceil ⌈ai/2⌉+⌈aj/2⌉。
对于第二种情况,需要遍历整个数组,比较最小操作数 m i n ( ⌈ a i / 2 ⌉ + ⌈ a i + 2 / 2 ⌉ , ⌈ ( a i − 1 ) / 2 ⌉ + ⌈ ( a i + 2 − 1 ) / 2 ⌉ + 1 ) min(\lceil a_i/2\rceil + \lceil a_{i+2}/2 \rceil,\lceil (a_i-1)/2\rceil + \lceil (a_{i+2} - 1)/2 \rceil + 1) min(⌈ai/2⌉+⌈ai+2/2⌉,⌈(ai−1)/2⌉+⌈(ai+2−1)/2⌉+1) ( 1 ≤ i ≤ n − 2 ) (1\leq i \leq n-2) (1≤i≤n−2) , ⌈ ( a i − 1 ) / 2 ⌉ + ⌈ ( a i + 2 − 1 ) / 2 ⌉ + 1 ) \lceil (a_i-1)/2\rceil + \lceil (a_{i+2} - 1)/2 \rceil + 1) ⌈(ai−1)/2⌉+⌈(ai+2−1)/2⌉+1) 的意思是,先为 a i + 1 a_{i+1} ai+1 进行一次操作,目的是为了让 a i a_i ai 与 a i + 2 a_{i+2} ai+2 同时减 1 1 1 。
对于第三种情况,也需要遍历整个数组,比较最小操作数,假设对 a i a_i ai 进行 x x x 次操作,对 a i + 1 a_{i+1} ai+1 进行 y y y 次操作,则有如下两个不等式
- 2 ∗ x + y ≥ a i 2 * x + y \geq a_i 2∗x+y≥ai
- x + 2 ∗ y ≥ a i + 1 x + 2 *y \geq a_{i+1} x+2∗y≥ai+1
合并不等式 3 ∗ x + 3 ∗ y ≥ a i + a i + 1 ⟹ x + y ≥ ( a i + a i + 1 ) / 3 ⟹ x + y = ⌈ ( a i + a i + 1 ) / 3 ⌉ 3 * x + 3 * y \geq a_i + a_{i+1} \implies x + y \geq (a_i + a_{i+1}) / 3 \implies x + y = \lceil (a_i + a_{i+1}) / 3 \rceil 3∗x+3∗y≥ai+ai+1⟹x+y≥(ai+ai+1)/3⟹x+y=⌈(ai+ai+1)/3⌉ ,此处一定要注意 x + y x + y x+y 不一定是正确的操作数 ( a i = 0 , a i + 1 = 3 ) (a_i = 0,a_{i+1} = 3) (ai=0,ai+1=3),所以最终的表达式为 m a x ( ⌈ ( a i + a i + 1 ) / 3 ⌉ , ⌈ a i / 2 ⌉ , ⌈ a i + 1 / 2 ⌉ ) max(\lceil (a_i + a_{i+1}) / 3 \rceil,\lceil a_i / 2 \rceil,\lceil a_{i+1}/2 \rceil) max(⌈(ai+ai+1)/3⌉,⌈ai/2⌉,⌈ai+1/2⌉) ,最后取每个结果的 m i n min min。
#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;
const int N = 2e5 + 10;
int a[N];
int main(){
int n;
int d1 = 0x3f3f3f3f,d2 = 0x3f3f3f3f;
scanf("%d",&n);
for(int i=1;i<=n;i++) {
scanf("%d",&a[i]);
if(d1 > a[i]) {
d2 = d1;
d1 = a[i];
}
else if(d2 > a[i]) {
d2 = a[i];
}
}
int res = d1 / 2 + d2 / 2;
if(d1 % 2) res ++;
if(d2 % 2) res ++;
for(int i=2;i<n;i++) {
double A = a[i - 1];
double B = a[i];
double C = a[i + 1];
res = min(res,(int)min(ceil((A-1)/2)+ceil((C-1)/2) + 1,ceil(A/2)+ceil(C/2)));
res = min(res,(int)max({ceil(A / 2),ceil(B / 2),ceil((A+B)/3)}));
res = min(res,(int)max({ceil(C / 2),ceil(B / 2),ceil((C+B)/3)}));
}
res = min(res,(int)max({ceil((double)a[1] / 2),ceil((double)a[2] / 2),ceil((double)(a[1]+a[2])/3)}));
res = min(res,(int)max({ceil((double)a[n] / 2),ceil((double)a[n-1] / 2),ceil((double)(a[n]+a[n-1])/3)}));
printf("%d\n",res);
return 0;
}
/*
2
0 3
*/