题意:
攻击一行数,任意选择一个,攻击某位置可以使得该位置-2,相邻位置-1.求使得两个为0的最小值。
题解:
把所有可能最小的情况求出,再取最小。
大概推推可以发现,最小值会出现这三种情况中:
1.相邻:
假定其为a,b。
如果a大于等于b的两倍,那么mmin此时与(a+1)/2比较。因为只对a操作b一定能归0。b大于等于二倍的a类似。(wa的原因就是忽略了这种情况55)
如果都不满足呢。其实是和除以3向上取整,因为对一次操作来说,其实是对和作用了3。写个例子就能很清楚的推出了。
2.相隔1:
假设顺序为a,b,c。
求出a,c最小的,可以对中间操作该次数使得最小归0,另一个减少它。然后对剩余值除以2向上取整即可。
3.其它。
那就是最小和次小分别进行除以2向上取整操作即可。
代码如下:
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
#define sc scanf
#define pr printf
const int maxn=2e5+7;
int a[maxn];
#define ll long long
int main() {
int n;cin>>n;
int mmin=INT_MAX;
int mini=-1;
int mmin1=INT_MAX;
int mmin2=INT_MAX;
for(int i=0;i<n;i++){
sc("%d",&a[i]);
if(i>0){//相邻最小
if(a[i]>=2*a[i-1])mmin=min(mmin,(a[i]+1)/2);
else if(a[i-1]>=2*a[i])mmin=min(mmin,(a[i-1]+1)/2);
else
mmin=min(mmin,(a[i]+a[i-1]+2)/3);
}
if(i>1&&a[i-1]>min(a[i-2],a[i])){//间隔为1最小
int b=max(a[i-2],a[i]),s=min(a[i-2],a[i]);
mmin=min(mmin,s+((b-s)+1)/2);
}
if(i==1){//找出最小的两个数。mmin2最小,mmin2次小。
mmin1=max(a[0],a[1]);
mmin2=min(a[0],a[1]);
}
else if(i>1){
if(mmin2>a[i]&&mmin1>a[i]){
mmin1=mmin2;
mmin2=a[i];
}
else if(mmin1>a[i])mmin1=a[i];
}
}
mmin=min(mmin,(mmin1+1)/2+(mmin2+1)/2);
cout<<mmin<<endl;
return 0;
}