题意:一组数据,1 - n ,可以选一个目标位置,x 使其 - 2 ,同时 x - 1 , x + 1 减 1,求最小操作次数,使得原数组出现两个0.
分类:
1. 这两个位置 , 不相邻 , 那么就是独立,每个都通过 - 2 变成 0 , 那么一定是最小的两个数,可以满足这个条件 , 排序后的 (v[1] + 1) / 2 + (v[2] + 1) / 2)为这种情况的最小值.
2.相隔为1 , 如果都是奇数,那么先操作中间两边都-1,变成偶数,每次都是 - 2 ,总操作数 - 1,
如果是其他情况, 那么他的最小值是 分别把每一个变成 0 。
3.相邻,ai (a) , ai-1(b) ,
假设 a > b;
一个-2 ,另一个 - 1,如果 a >= 2*b ,一直对a操作,a变成0,b也一定是0,那么就得到 --- >
(a + 1) / 2 为这个情况的最小值
a < 2b , 那么 a - 2 * x = b - x; 得到 x = a - b; 因为 a < 2b 所以 a - b < b; x取值是一个小于b的数,说明在b变为0之前,可以有a == b ,当 a == b时 每次操作都能保证 |a - b| <= 1,那么最后结果一定是 a = 0,b = 1 ; a = 0 ,b = 0; a = 1,b = 1;a = 1,b = 0;其中之一,对于不是 a = 0,b = 0的情况,需要多操作一次,也就是 % 3有余数时,需要 + 1,那么就是上除整的操作,那么最小值为 (a + b + 2) / 3;
综上
ans = min ((a + b + 2) / 3 , (a + 1) / 2 , (v[1] + 1) / 2 + (v[2] + 1) / 2);
代码如下:
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
int a[3000010];
int b[3000010];
void solve()
{ int n;
cin >> n;
for(int i = 1; i <= n ; i ++ )
{
cin >> a[i];
b[i] = a[i];
}
sort(b+1,b+1+n);
ll ans = (b[1] + 1) / 2 + (b[2] + 1) / 2;
for(int i = 2; i <= n ; i ++ )
{
ll t;
int k1 = a[i] ;
int k2 = a[i-1] ;
if(max(k1,k2) >= 2*min(k1,k2))
{
ans = min(int(ans) ,(max(k1,k2) + 1)/2);
}
else
{
ans = min((int)ans , (k1 + k2 + 2) / 3);
}
if(i != n)
{
t = min(a[i-1],a[i+1]);
t += (max(a[i-1],a[i+1]) - min(a[i-1],a[i+1]) + 1) / 2;
ans = min(ans , t);
}
}
cout << ans << endl;
return ;
}
int main()
{
solve();
}