题目描述
OI 大师抖儿在夺得银牌之后,顺利保送 pku。这一天,抖儿问长者:“我虽然已经保送了,但我的志向是为国家健康工作五十年。请问我应该怎样变得更有力气?”
长者回答:“你啊,Too Young Too Simple,Sometimes Naive!如果你想要我教你,你要先进行艰苦的修行。”
长者的住宅中有一堵长度为 n 的墙。每天抖儿起床修行,会选择一段长度为 x 的区间染成白色。长者的住宅附近有一群香港记者,为了借助抖儿拜访长者,第 i 天香港记者会将区间[l i ,r i ]染成白色来讨好抖儿(也就是说,每天墙会被抖儿和香港记者各染一次)。现在抖儿已经预先知道了香港记者的动向,他想知道他最少几天就能把墙全部染白,完成修行。
输入
第一行三个整数 n,m,x,分别表示墙的长度,天数和区间的长度。
接下来 m 行,每行两个整数 l i 、r i ,表示香港记者在第 i 天会将区间[l i ,r i ]染成白色。
输出
一行一个整数,表示抖儿最少几天能把墙全部染白。如果 m 天之后依然无法染白,则输出“Poor Douer!”
样例输入
10 3 3
2 5
4 8
9 10
样例输出
2
对于所有的数据,保证 n≤1018 ,m≤100000,x≤n 且数据随机
题解
二分答案。
二分需要的天数mid,然后把前mid天的区间排序,随便搞搞就可以了。
注意x=0 的情况要特判一下。
#include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define ll long long const int maxm=100000+50; ll n,m,x; struct A{ll l,r;}a[maxm]; struct B{ll l,r;}b[maxm]; int cmp(const B &a,const B &b){ if(a.l==b.l) return a.r<b.r; return a.l<b.l; } bool check(int len){ memset(b,0,sizeof(b)); ll ans=0,R=0,sum=0; for(int i=1;i<=len;i++) b[i].l=a[i].l,b[i].r=a[i].r; sort(b+1,b+1+len,cmp); if(x==0){ if(b[1].l!=1) return false; if(b[len].r!=n) return false; for(int i=1;i<=len;i++){ if(b[i].l>R+1) return false; R=max(R,b[i].r); } if(R!=n) return false; return true; } for(int i=1;i<=len;i++){ if(b[i].l>R+1){ sum=(b[i].l-R-1)/x; if((b[i].l-R-1)%x!=0) sum++; } else sum=0; R=max(b[i].r,sum*x+R); ans+=sum; if(ans>len) return false; } sum=(n-R)/x; if((n-R)%x!=0) sum++; if(n>R) ans+=sum; if(ans>len) return false; return true; } template<typename T>void read(T& aa){ char cc; ll ff;aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int main(){ // freopen("liqi.in","r",stdin); // freopen("liqi.out","w",stdout); read(n),read(m),read(x); for(int i=1;i<=m;i++) read(a[i].l),read(a[i].r); int l=0,r=m; if(!check(m)){ cout<<"Poor Douer!"<<endl; return 0; } while(l<=r){ int mid=l+r>>1; if(check(mid)) r=mid-1; else l=mid+1; } cout<<l<<endl; return 0; }