题意
在长n的序列a中保留k个数,此时令新的子序列为s
统计所有奇数索引上的最大值和偶数索引上的最小值,二者取小就是花费
你要让这个花费最小
分析
二分,分为奇数索引贡献答案和偶数索引贡献答案
Ⅰ.奇数索引贡献答案的最小值
此时先二分一个答案mid,然后去check
因为奇数索引要选(k+1)/2个数,而且选的数不能比mid大
否则就认定失败(因为是一直取max)
那么我们从索引1开始往后看,一旦发现这个数小于mid就赶快拿下来
这个索引拿了给奇数索引,下一个数就马上给偶数索引,这样让后面奇数的选择更多
不管那个数多么小都给偶数索引,因为相邻的两个小数肯定只能拿一个
因为贡献相同,肯定拿前面的那个给后面留出更多位置选择
结束后,检查选的奇数索引和偶数索引是否能达到(k+1)/2和k/2
Ⅰ.偶数索引贡献答案的最小值
因为是偶数索引,那么第一个数肯定选给奇数索引,留给偶数的选择空间才大
剩下的就和前面一样了,能选就选,选完留给奇数索引,往下继续选
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int a[maxn],b[maxn],n,k;
bool isok(int zhi)
{
int ji=0,ou=0;
for(int i=1;i<=n;i++)//奇数情况
if(a[i]<=zhi)
{
ji++,i++;
if(i<=n) ou++;
}
if(ji>=(k+1)/2&&ou>=k/2) return true;
ji=1,ou=0;
for(int i=2;i<=n;i++)//偶数情况
if(a[i]<=zhi)
{
ou++,i++;
if(i<=n) ji++;
}
if(ji>=(k+1)/2&&ou>=k/2) return true;
return false;
}
int main()
{
cin >> n >> k;
for(int i=1;i<=n;i++)
{
cin >> a[i];
b[i]=a[i];
}
sort(b+1,b+1+n);
int l=1,r=n,mid,ans=1e9;
while(r>=l)
{
mid=l+r>>1;
if( isok(b[mid]) ) r=mid-1,ans=b[mid];
else l=mid+1;
}
cout<<ans;
}