区间问题
区间选点
题目描述
给定N个闭区间[ai,bi],请你在数轴上选择尽量少的点,使得每个区间内至少包含一个选出的点。输出选择的点的最小数量。
位于区间端点上的点也算作区间内。
输入格式
第一行包含整数N,表示区间数。接下来N行,每行包含两个整数ai,bi,表示一个区间的两个端点。
输出格式
输出一个整数,表示所需的点的最小数量。
数据范围
1≤N≤10 ^ 5,
−10 ^ 9 ≤ ai,bi ≤ 10 ^ 9
输入样例:
3
-1 1
2 4
3 5
输出样例:
2
#include <iostream>
#include <algorithm>
using namespace std;
const int N=1e5+10;
int n;
struct Range
{
int l,r;
bool operator<(const Range &W)const
{
return r<W.r;//右端点从小到大排序
}
}range[N];
int main()
{
cin>>n;
for (int i=0;i<n;i++)
{
int l,r;
cin>>l>>r;
range[i]={l,r};
}
sort(range, range+n);
int res=0, ed=-2e9;
//ed:上一个点的坐标
//res:选择点的数量
for (int i=0;i<n;i++)
{
if (range[i].l>ed)
{
res++;
ed=range[i].r;
}
}
cout<<res<<endl;
}
最大不相交区间数量
代码同上
区间分组
题目描述
给定N个闭区间[ai,bi],请你将这些区间分成若干组,使得每组内部的区间两两之间(包括端点)没有交集,并使得组数尽可能小。输出最小组数。
输入格式
第一行包含整数N,表示区间数。接下来N行,每行包含两个整数ai,bi,表示一个区间的两个端点。
输出格式
输出一个整数,表示最小组数。
数据范围
1≤N≤105, −109≤ai≤bi≤109
输入样例:
3
-1 1
2 4
3 5
输出样例: 2
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
const int N=1e5+10;
int n;
struct Range
{
int l,r;
bool operator <(const Range &W)const
{
return l<W.l;//左端点从小到大排序
}
}range[N];
int main()
{
cin>>n;
for (int i=0;i<n;i++)
{
int l,r;
cin>>l>>r;
range[i]={l,r};
}
sort(range,range+n);
priority_queue<int, vector<int>, greater<int> > heap;
//小根堆,维护每组区间右端点的最大值
for (int i=0;i<n;i++)
{
if (heap.empty() || heap.top()>=range[i].l) heap.push(range[i].r);
else
{
int t=heap.top();
heap.pop();
heap.push(range[i].r);
}
}
cout<<heap.size();
}
区间覆盖
题目描述 给定N个闭区间[ai,bi]以及一个线段区间[s,t],请你选择尽量少的区间,将指定线段区间完全覆盖。
输出最少区间数,如果无法完全覆盖则输出-1。
输入格式
第一行包含两个整数s和t,表示给定线段区间的两个端点。第二行包含整数N,表示给定区间数。
接下来N行,每行包含两个整数ai,bi,表示一个区间的两个端点。
输出格式
输出一个整数,表示所需最少区间数。如果无解,则输出-1。
数据范围
1≤N≤105, −109≤ai≤bi≤109, −109≤s≤t≤109
输入样例:
1 5
3
-1 3
2 4
3 5
输出样例:
2
将所有区间按左端点从小到大排序
从前往后依次枚举每个区间,在所有能覆盖start的区间中,选择右端点最大的区间,然后将start更新成右端点的最大值
#include <iostream>
#include <algorithm>
using namespace std;
const int N=1e5+10;
int n;
int st,ed;
struct Range
{
int l,r;
bool operator <(const Range &W)const
{
return l<W.l;//左端点从小到大排序
}
}range[N];
int main()
{
cin>>st>>ed;
cin>>n;
for (int i=0;i<n;i++)
{
int l,r;
cin>>l>>r;
range[i]={l,r};
}
sort(range, range+n);
int res=0;
bool success=false;
for (int i=0;i<n;i++)
{
int j=i,r=-2e9;
while(j<n && range[j].l<=st)
{
r=max(r,range[j].r);
j++;
}
if (r<st)
{
res=-1;
break;
}
res++;
if (r>=ed)
{
success=true;
break;
}
st=r;
i=j-1;
}
if (success) cout<<res;
else cout<<-1;
}
Huffman树
权值最小的两个点在树中深度最深,且可以互为兄弟(不一定)
每次先合并最小的两个点
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
int main()
{
int n;
cin>>n;
priority_queue<int, vector<int>, greater <int> > heap;//小根堆
while(n--)
{
int x;
cin>>x;
heap.push(x);
}
int res=0;
while(heap.size()>1)
{
int a=heap.top(); heap.pop();
int b=heap.top(); heap.pop();//拿出最小的两个点
res+=a+b;
heap.push(a+b);
}
cout<<res;
}
排序不等式
排队打水
题目描述
有 n 个人排队到 1 个水龙头处打水,第 i 个人装满水桶所需的时间是 ti,请问如何安排他们的打水顺序才能使所有人的等待时间之和最小?
输入样例
7
3 6 1 4 2 5 7
输出样例
56
按照从小到大的顺序排队,总时间最小
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N=1e5+10;
int n;
int t[N];
int main()
{
cin>>n;
for (int i=0;i<n;i++)
cin>>t[i];
sort(t,t+n);
LL res=0;
for (int i=0;i<n;i++)
res+=t[i]*(n-i-1);
cout<<res;
}
绝对值不等式
货仓取在中位数或中间两个数之间
#include <iostream>
#include <algorithm>
using namespace std;
const int N=1e5+10;
int n;
int a[N];
int main()
{
cin>>n;
for (int i=0;i<n;i++)
cin>>a[i];
sort(a,a+n);
int res=0;
for (int i=0;i<n;i++)
res+=abs(a[i]-a[n/2]);
cout<<res;
}
推公式
按照wi+si从小到大的顺序排,最大的危险系数一定是最小的
#include <iostream>
#include <algorithm>
using namespace std;
typedef pair<int, int> PII;
const int N=5e4+10;
int n;
PII cow[N];
int main()
{
cin>>n;
for (int i=0;i<n;i++)
{
int w,s;
cin>>w>>s;
cow[i]={w+s,w};
}
sort(cow,cow+n);
int res=-2e9,sum=0;
for (int i=0;i<n;i++)
{
int w=cow[i].second, s=cow[i].first-w;
res=max(res,sum-s);
sum+=w;
}
cout<<res;
}