[CF1601D]Difficult Mountain

Difficult Mountain

题解

显然,我们可以把所有的人分成两类,一类是 a ⩽ s a\leqslant s as,一类是 a > s a>s a>s
对于 a ⩽ s a\leqslant s as的部分,我们有一个简单的贪心策略,将所有的按照 s s s排序,越大的越后面。
显然,后一个选择的 s s s是大于前面所有的 s s s的,自然是大于前面所有的 a a a的,所以只要它的 s s s大于 d d d,那么它一定是可以被选择的。
而对于 a > s a>s a>s的部分,我们也有一个简单的贪心策略,将所有的按照 a a a排序,能选则选。
显然,在这种情况下,所有我们选择的 ( a , s ) (a,s) (a,s)都可以被看成许多不相交的线段。
我们可以考虑将第二部分的所有 ( a , s ) (a,s) (a,s)都当成线段插入到部分一里面去,如果该线段没有影响到部分一的选择,那么它肯定可以被选择。
也就是当我们进行到第一个 s i s_{i} si不小于该线段的 a a a时,且其 s s s不小于当前的 d d d,我们可以将该线段加入答案,因为它不会对部分一的选择造成任何影响,而我们的第二类也是按我们的贪心方法排序,也是最优的。
而当我们的第二类影响到第一类时,我们可以发现,一个第二类线段最少会影响一个,但它最多只能贡献一个,因为其它贡献线段是与它不相交的,所以并不会影响它影响的第一类选择。
所以我们当然可以将那个第二类线段替换成第一类线段。
在这种情况下,所有被选择的第二类线段都不会对第一类造成影响。
显然,该方法可以在排序后通过双指针维护。

时间复杂度 O ( n log ⁡   n ) O\left(n\log\,n\right) O(nlogn)

源码

#pragma GCC optimize(2, 3, "Ofast")
#include<bits/stdc++.h>
using namespace std;
#define MAXN 500005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long LL;
typedef unsigned long long uLL;       
const int INF=0x3f3f3f3f;       
const int mo=998244353;
const int inv2=499122177;
const int jzm=2333;
const int zero=10000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
typedef pair<LL,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int n,d,tot1,tot2,ans;
struct ming{int a,s;}p1[MAXN],p2[MAXN];
bool cmp1(ming x,ming y){return x.s<y.s;}
bool cmp2(ming x,ming y){return x.a<y.a;}
signed main(){
	read(n);read(d);
	for(int i=1;i<=n;i++){
		int s,a;read(s);read(a);
		if(a<=s)p1[++tot1]=(ming){a,s};
		else p2[++tot2]=(ming){a,s};
	}
	sort(p1+1,p1+tot1+1,cmp1);
	sort(p2+1,p2+tot2+1,cmp2);
	int i,j;
	for(i=1,j=1;i<=tot1;i++){
		while(j<=tot2&&p2[j].a<=p1[i].s){if(d<=p2[j].s)ans++,d=p2[j].a;j++;}
		if(p1[i].s>=d)d=max(d,p1[i].a),ans++;
	}
	while(j<=tot2){if(d<=p2[j].s)ans++,d=p2[j].a;j++;}
	printf("%d\n",ans);
	return 0;
}

谢谢!!!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值