有 C C C个奶牛晒太阳,但是第 i i i个奶牛有一个要求,就是阳光值必须在 [ l i , r i ] [l_i,r_i] [li,ri]之间,才能享受晒太阳。阳光强度开始都是 ∞ \infin ∞。有 S S S种防晒霜,第 i i i种珂以让一个奶牛收到的阳光保持在 t i t_i ti,数量有 c i c_i ci个。每个奶牛只能涂一种防晒霜,求最多多少奶牛能享受晒太阳。
第一行两个正整数 C , S C,S C,S,如题。
接下来 C C C行每行两个正整数,第 i i i行是 l i l_i li和 r i r_i ri
再接下来 S S S行每行两个正整数,第 i i i行是 t i t_i ti, c i c_i ci
如题。输出最多多少奶牛能够晒到日光浴。
输入
3 2
3 10
2 5
1 5
6 2
4 1
输出
2
看到标签写着“蒟阵乘法”,"网络流"什么的把我吓的半死。。。
仔细想想,好像贪心就珂以了。
防晒霜的 t i t_i ti肯定是要排序,和奶牛的区间肯定要排序,要不然没处入手。奶牛的区间很明显是按 r r r升序排序。如果我们有一个十分优秀的排序防晒霜的方法,那么我们只要 O ( C ) O(C) O(C)枚举一个牛, O ( S ) O(S) O(S)枚举防晒霜,找到第一个就退出,就一定是最优解了。总复杂度 O ( C S ) O(CS) O(CS)直接过来。
那么, t i t_i ti是升序 or 降序?(一脸懵逼。。。
直觉想想,升序好像是对的。实际上,USACO是珂以看到实时成绩的,用升序AC了,用降序只过了样例。但是我们证明,或者意会明白:为什么一定要升序?
有点像刘汝佳小蓝书上的第一题:Dragon of Loowater,假设现在我们降序排序,如果我们有一个防晒霜的 t t t值很大,但是我们把它给了一个 r r r很小的奶牛,那么,后面 r r r更大的奶牛就缺少了选择的余地,十分不划算。更划算的方法应该是 t t t值相对小防晒霜的配 r r r值也相对小的防晒霜, t t t值相对大的防晒霜配 r r r值也相对大的奶牛,才对。
但是这个题和Dragon of Loowater不一样的地方在于,对于每一个奶牛,因为是一段区间,所以选择的防晒霜编号不一定单调不减,所以要每一次都重新枚举, O ( C S ) O(CS) O(CS)的。
代码:
#include
using namespace std;
namespace Flandle_Scarlet
{
#define N 2600
struct cow
{
int l,r;
}C[N];bool operator<(cow a,cow b) {return a.r<b.r;}
struct SPF
{
int c,t;
}S[N];bool operator<(SPF a,SPF b) {return a.t<b.t;}
int c,s;
void Input()
{
scanf("%d%d",&c,&s);
for(int i=1;i<=c;++i)
{
scanf("%d%d",&C[i].l,&C[i].r);
}
for(int i=1;i<=s;++i)
{
scanf("%d%d",&S[i].t,&S[i].c);
}
sort(C+1,C+c+1);
sort(S+1,S+s+1);
}
void Solve()
{
int ans=0;
for(int i=1;i<=c;++i)
{
for(int j=1;j<=s;++j)
{
if (S[j].t>=C[i].l and S[j].t<=C[i].r and S[j].c)
{
--S[j].c;
++ans;
break;
}
}
}
printf("%d\n",ans);
}
void Main()
{
if (0)
{
freopen("","r",stdin);
freopen("","w",stdout);
}
Input();
Solve();
}
};
main()
{
Flandle_Scarlet::Main();
return 0;
}
回到总题解界面