题意:
给定一个数组,然后让你选择m个数,从max(m1,m3,m5…)和max(m2,m4,m6)取一个最小值,就是求这个最小值。
思考:
首先看到求最小值,可以想到二分,但是又该如何做呢?又注意到式子为什么是这样的,就会想到目前我只看奇数位,偶数位是什么数我不管,或者只看偶数位,奇数位是什么我不管。然后就是分两种情况去二分,看看数组中是否有足够的数满足二分条件。但是要注意个细节,如果只看奇数位,如果m是偶数,那么选完最后一个奇数之后,后面还要留一位。如果只看偶数位,如果m是奇数,那么同样选完最后一个奇数之后,后面还要留一位。还有一点就是比赛中会考虑如果拿这个不如拿下一个更好怎么办?准确的说,根据贪心其实每次能拿就拿这就是最优的,针对权值都是1的时候,能拿就拿这就是最优的。
代码:
int T,n,m;
int va[N];
int minn = inf;
bool check_odd(int mid);
bool check_even(int mid);
signed main()
{
IOS;
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>va[i];
int l = 0,r = 1e9;
while(l<r)
{
int mid = (l+r)>>1;
if(check_even(mid)) r = mid;
else l = mid+1;
}
minn = min(minn,r);
l = 0,r = 1e9;
while(l<r)
{
int mid = (l+r)>>1;
if(check_odd(mid)) r = mid;
else l = mid+1;
}
minn = min(minn,r);
cout<<minn;
return 0;
}
bool check_even(int mid)
{
int res = 0;
for(int i=2;i<=n;i++)
{
if(va[i]<=mid)
{
res++;
if(res>=m/2)
{
if(m%2==0) return true;
if(i<n) return true;
else return false;
}
i++;
}
}
return false;
}
bool check_odd(int mid)
{
int res = 0;
for(int i=1;i<=n;i++)
{
if(va[i]<=mid)
{
res++;
if(res>=(m+1)/2)
{
if(m%2!=0) return true;
if(i<n) return true;
else return false;
}
i++;
}
}
return false;
}
总结:
要注意到为什么这样给公式,要想到那些可行的方案,对于细节的处理。