D. Odd-Even Subsequence(奇偶二分)

题意

n a k , s 在长n的序列a中保留k个数,此时令新的子序列为s

, 统计所有奇数索引上的最大值和偶数索引上的最小值,二者取小就是花费

你要让这个花费最小

分析

, 二分,分为奇数索引贡献答案和偶数索引贡献答案

. \color{Red}Ⅰ.奇数索引贡献答案的最小值

m i d , c h e c k 此时先二分一个答案mid,然后去check

( k + 1 ) / 2 , m i d 因为奇数索引要选(k+1)/2个数,而且选的数不能比mid大

( m a x ) 否则就认定失败(因为是一直取max)

1 , m i d 那么我们从索引1开始往后看,一旦发现这个数小于mid就赶快拿下来

, , 这个索引拿了给奇数索引,下一个数就马上给偶数索引,这样让后面奇数的选择更多

, 不管那个数多么小都给偶数索引,因为相邻的两个小数肯定只能拿一个

, 因为贡献相同,肯定拿前面的那个给后面留出更多位置选择

, ( k + 1 ) / 2 k / 2 结束后,检查选的奇数索引和偶数索引是否能达到(k+1)/2和k/2

. \color{Red}Ⅰ.偶数索引贡献答案的最小值

, , 因为是偶数索引,那么第一个数肯定选给奇数索引,留给偶数的选择空间才大

, , , 剩下的就和前面一样了,能选就选,选完留给奇数索引,往下继续选

#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;
} 

猜你喜欢

转载自blog.csdn.net/jziwjxjd/article/details/106881099