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

题意

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

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

你 要 让 这 个 花 费 最 小 你要让这个花费最小

分析

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

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

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

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

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

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

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

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

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

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

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

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

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

#include 
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<

你可能感兴趣的:(div题解)