题目大意
你每天可以讲一段长度为$x$的区间染色,每天有香港记者将一段区间染色,询问最少几天可以将区间全部染色。(每个点全部被染色)
题目吐槽
暴力膜蛤不可取,膜蛤不当必被续!
题目分析
显然我们可以二分答案,验证能否在$mid$天内全部染色。
判定的时候我们可以采用经典的贪心区间覆盖。
先用$n\log n$将区间按左端点排序,然后扫描右端点。
若有分离的区间,用自己染色补上,如果补上的次数大于$mid$就判定失败。
注意$x=0$的情况,小心Math Error
。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| #include<algorithm> #include<iostream> #include<iomanip> #include<cstring> #include<cstdlib> #include<vector> #include<cstdio> #include<cmath> #include<queue> using namespace std; typedef long long LL; inline const LL Get_Int() { LL num=0,bj=1; char x=getchar(); while(x<'0'||x>'9') { if(x=='-')bj=-1; x=getchar(); } while(x>='0'&&x<='9') { num=num*10+x-'0'; x=getchar(); } return num*bj; } struct Interval { LL l,r; bool operator < (const Interval b) const { return l<b.l||(l==b.l&&r<b.r); } } a[100005],tmp[100005]; LL n,m,x; bool Check(int Limit) { for(int i=1; i<=Limit; i++)tmp[i]=a[i]; sort(tmp+1,tmp+Limit+1); LL right=1,ans=0; if(x) { tmp[0].l=tmp[0].r=0; tmp[Limit+1].l=tmp[Limit+1].r=n+1; for(int i=1; i<=Limit+1; i++) { right=max(right,tmp[i-1].r+1); if(tmp[i].l>right) { LL v=ceil(double(tmp[i].l-right)/x); ans+=v; right+=v*x; } if(ans>Limit)return false; } } else { tmp[0].l=tmp[0].r=0; tmp[Limit+1].l=tmp[Limit+1].r=n+1; for(int i=1; i<=Limit+1; i++) { right=max(right,tmp[i-1].r+1); if(tmp[i].l>right)return false; } } return true; } int main() { n=Get_Int(); m=Get_Int(); x=Get_Int(); for(int i=1; i<=m; i++) { a[i].l=Get_Int(); a[i].r=Get_Int(); } int Left=1,Right=m; while(Left<=Right) { int mid=(Left+Right)>>1; if(Check(mid))Right=mid-1; else Left=mid+1; } if(Left==m+1)puts("Poor Douer!"); else printf("%d\n",Left); return 0; }
|