正文
题面
这题的翻译很不靠谱,直接给
c
o
v
e
r
cover
cover 翻译漏了,以至于完全不可读,我拿AI重翻了一下:
思路
看起来像是一个贪心,但是具体怎么搞呢?
读题的时候,我对其中两句话很敏感:
- 每个奶牛只能抹一瓶防晒霜。
- 而刚开始的阳光的强度非常大,奶牛都承受不住。
结合这两句,观察题目,奶牛能接受的范围可以抽象成一条线段,而防晒霜则是一个点,每个线段必须分到一个能覆盖的点。是的,这是一个很经典的区间覆盖。
那就应该考虑区间覆盖的重中之重——选择用于排序的端点!(本人一开始分析上草草了事,WA):
我们先固定防晒霜就是从小到大排序。
①如果我们以左端点为基准,从小到大排序:
如图,灰色圆圈表示防晒霜,黑色线段表示奶牛接受范围,发现这是一个反例。
②如果我们以右端点为基准,从小到大排序:
图为一种情况,易证可以得出最优解:优先考虑了先变为考虑不到的线段。
分析完上述内容,这题思路便清晰了。
实现
#include <iostream>
#include <algorithm>
using namespace std;
const int N=2510;
typedef pair<int,int> PII;
int C,L,ans;
PII a[N],f[N];
bool cmp(PII x,PII y)
{
return x.first<y.first;
}
bool cmp2(PII x,PII y)
{
return x.second<y.second;
}
int main()
{
cin>>C>>L;
for(int i=1;i<=C;i++)
{
cin>>a[i].first>>a[i].second;
}
sort(a+1,a+C+1,cmp2);
for(int i=1;i<=L;i++)
{
cin>>f[i].first>>f[i].second;
}
sort(f+1,f+L+1,cmp);
for(int i=1;i<=C;i++)
{
for(int j=1;j<=L;j++)
{
//若点在区间内且这种防晒霜没用完则减少一瓶防晒霜数量,多一头牛可以享受
if(a[i].first<=f[j].first&&a[i].second>=f[j].first&&f[j].second>0)
{
f[j].second--;
ans++;
break;
}
}
}
cout<<ans;
return 0;
}
总结
本题考察重点主要在题面到算法的转换,以及区间覆盖实现上的分析。
做算法题(尤其是OI赛制下),还是要简单证明一下关键内容。写题不严谨,出分两行泪。
不过区间覆盖类题目还是很相似的,做多之后可直接套用板子(当然要是和我一样忘光了,多推几次可以加深理解挺好的)。
附录
2024.5.3 博客完成
2024.5.17 博主的盆友在读博客时发现配图出锅,指出后本人修正。