1843E - Tracking Segments

发布时间 2023-07-11 22:31:51作者: qbning

Problem - E - Codeforces

题意是现在有n个0,给你m段序列,然后给你q次操作,每次操作给一个x,把第x个0变成1,问你最少几次操作能出现一段序列里的1的数量大于0的数量,如果不存在,输出-1

对于操作数是一个递增序列。如果第k次操作后正好可行,那么就不用管k+1及以后了。

所以可以使用二分来解决。

一开始在check函数犯了一个错误,当check k时,成功的条件是当前段里的1的数目*2>段长度,而不应该是(当前段里的1的数目>=k&&k*2>段长度)

 

代码

#include<iostream>
#include<cstring>
#define int long long
using namespace std;
int n,m,q;
int b[100005];
int a[100005],e[100005];
struct seg
{
	int l,r;
}c[100005];
inline bool check(int k)
{
	memset(e,0,sizeof(e));
	for(int i=1;i<=k;i++)
		e[a[i]]=1; 
	for(int i=1;i<=n;i++)
		b[i]=b[i-1]+e[i];
	for(int i=1;i<=m;i++)
	{
		int l=c[i].l,r=c[i].r;
		if((b[r]-b[l-1])*2>r-l+1)
		//if(b[r]-b[l-1]>=k&&r-l+1<2*k)错误示例 
			return 1;
	}
	return 0;
}
void solve()
{
	cin>>n>>m;
	for(int i=1;i<=m;i++)
		cin>>c[i].l>>c[i].r;
	cin>>q;
	for(int i=1;i<=q;i++)
		cin>>a[i];
	int l=1,r=q;
	while(l<r)//log(q)
	{
		int mid=(l+r)>>1;
		if(check(mid))r=mid;
		else l=mid+1;
	}
	if(check(l))
		cout<<l<<endl;
	else cout<<-1<<endl;
}
signed main()
{
	int t;
	cin>>t;
	while(t--)
		solve();
	return 0;
}