【贪心】选择尽量多的不相交区间

参考链接

问题:跟定n个开区间(a,b)或闭区间a,b,选择尽量多个区间,且这些区间互不相交。

贪心策略:将每个区间按右端点从小到大排序。遍历所有的区间,如果当前区间的左端点和最长区间的右端点相冲突,直接放弃,否则选取。
模版题

AC代码

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
struct qj{
	int s,f;
	friend bool operator<(qj x,qj y){
		if(x.f==y.f) return x.s<y.s;
		return x.f<y.f;
	}
}a[maxn]; 
int n,ans,last;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i].s>>a[i].f;
	sort(a+1,a+n+1);
	last=1,ans=1;
	for(int i=2;i<=n;i++){
		if(a[i].s>=a[last].f){
			++ans;
			last=i;
		}
	}
	cout<<ans;
    return 0;
}

进阶题1

这题我们根据小岛和半径确定区间的左端点和右端点。然后套模版选择区间。但这道题有一个小坑是如果半径d<y,是覆盖不到的,输出-1。

AC代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int n,d,c;
struct node{
	double s,f;
	friend bool operator<(node a,node b){
		return a.f<b.f;
	}
}pos[1005];
int main(){
	cin>>n>>d;
	while(n&&d){
		++c;
		bool flag=0;
		for(int i=1;i<=n;i++){
			int x,y;
			cin>>x>>y;
			if(y>d) flag=1;
			pos[i].s=x*1.0-sqrt(d*d-y*y);
			pos[i].f=x*1.0+sqrt(d*d-y*y);
		} 
		if(flag){
			cout<<"Case "<<c<<": "<<-1<<endl;
			cin>>n>>d;
			continue; 
		}
		sort(pos+1,pos+n+1);
		int last=0,ans=0;
		pos[last].f=-1e9;
		for(int i=1;i<=n;i++){
			if(pos[i].s>pos[last].f){
				++ans;
				last=i;
			}
		}
		cout<<"Case "<<c<<": "<<ans<<endl;
		cin>>n>>d;
	}
    return 0;
}

进阶题2

这题题目明确给出了不相交区间,我们不难想到模版题。但是这道题需要转一下弯:这里的区间是怎么构成的呢?

拿数据举例:

bash 复制代码
4 2
2 1 0 3

找权值为2的区间,我们不难想到前缀和的思想。开一个数组s,st存储a1^ a2 ^ ... ^ at的结果。找权值为2的区间l,r就是找sl-1^sr=2的l,r。

why? 因为同一个数异或偶数次,结果为0,sr的计算过程中有sl-1的计算,再异或一次sl-1,就抵消了a1 ^ ... ^ al-1的结果。sl-1 ^ sr求到的就是al^ ... ^ar的结果。

那怎么找满足sl-1^sr=k的区间l,r呢?我们按下标顺序枚举左端点,计算每个左端点找到与之匹配的右端点的条件:sr=sl-1 ^ k。

我们一步步拆解来说:
1:sr=sl-1 ^ k是什么?

要找sl-1 ^ sr=k,等号两边同时异或sl-1,得到的就是sr=k^sl-1,我们枚举l,sl-1已知,k已知,就看如果sr=k ^ sl-1说明l,r权值为k。

2:如何使用选择尽可能多不相交的区间?

a数组下标 0 1 2 3 4
元素值 0 2 1 0 3
s数组下标 0 1 2 3 4
元素值 0 2 3 3 0

我们另开一个数组h,初始化h数组元素为-1。当sl^k=i时,hi=l。这样当找到sr=i时,我们就可以通过数组h找到l,区间l+1,r就是一个满足权值为k的区间。另外,我们开个变量last(初始化为-1)记录上一个满足条件的区间右端点的值。如果当前区间满足条件,且左端点比上一个满足条件的区间的右端点要大说明两个区间不相交,答案+1。

举例来说,变量i遍历s数组,
· i=0,si=0,h0=-1,说明暂时没有匹配到满足的左端点,不处理。然后记录h2=0;
· i=1,s1=2,h2=0,匹配到了左端点为h2+1,然后看一下左端点的值是否大于last,是则ans++,last=i。然后记录h0=1;

h数组下标 0 1 2 3 4
元素值 1 -1 0 -1 -1

· i=2,si=3,h3=-1,说明暂时没有匹配到满足的左端点,不处理。然后记录h1=2;
· i=3,si=3,h3=-1,说明暂时没有匹配到满足的左端点,不处理。然后记录h1=3;

h数组:

h数组下标 0 1 2 3 4
元素值 1 3 0 -1 -1

· i=4,si=0,h0=1,匹配到了左端点为h0+1,大于last,ans++,last=i。于是找到了两个不相交的区间。记录h2=4。

h数组:

h数组下标 0 1 2 3 4
元素值 1 3 4 -1 -1

3:在代码实现上要注意: a<=2^20,s数组要开到2e6比较保险。

AC代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e6+5;
int n,k,a[maxn],s[maxn],h[maxn]; 
int main(){
	cin>>n>>k;
	for(int i=1;i<=n;i++) {
		cin>>a[i];
		s[i]=s[i-1]^a[i];
	}
	for(int i=0;i<=n;i++)h[i]=-1;
	h[0^k]=1;
	int last=0,ans=0;
	for(int i=1;i<=n;i++){
		if(h[s[i]]!=-1&&h[s[i]]>last) {
			++ans;
			last=i;
		}
		h[s[i]^k]=i+1;
	}
	cout<<ans;
    return 0;
}
相关推荐
fpcc几秒前
数据结构和算法—数学的应用
数据结构·c++·算法
皓月斯语4 分钟前
B4451 [GESP202512 四级] 建造 题解
数据结构·c++·算法·题解
z小猫不吃鱼41 分钟前
模型剪枝经典论文精读:DepGraph: Towards Any Structural Pruning
算法·机器学习·剪枝
Ulyanov1 小时前
Python实现6-DOF刚体仿真器(下)——环境扰动与控制闭环
开发语言·python·算法·系统仿真·雷达电子对抗·导引头
牧以南歌〆2 小时前
数据结构<八>链式队列
c语言·数据结构·算法
Reart2 小时前
Leetcode 188.买卖股票的最佳时机4(718)
后端·算法
2601_950760792 小时前
BCMA:急性髓系白血病免疫治疗的新型可行靶点
人工智能·算法·蛋白
一个初入编程的小白2 小时前
数据结构:队列和栈的相互实现
数据结构
Reart2 小时前
Leetcode 123.买卖股票的最佳时期3(内有随心谈,718)
后端·算法
可编程芯片开发3 小时前
基于RMDCFT算法的天基雷达空间机动目标检测方法MATLAB仿真,对比FRFT和DFT算法
算法