题解 P6281 【[USACO20OPEN] Social Distancing S】

· · 题解

USACO 2020 US Open 白银组T1 Social Distancing

原题面(英文):http://www.usaco.org/index.php?page=viewproblem2&cpid=1038

官方题解(英文):http://www.usaco.org/current/data/sol_socdist_silver_open20.html

题意简述

N 头奶牛,M 个互不相交的区间,奶牛只能在区间中且奶牛之间的最小间隔为 D,你需要最大化 D

题目分析

要求最大化最小值,很快可以看出是道二分答案的模板题。

那我们思路就是:

①因为题目未保证输入区间有序,以防万一先排个序,由于互不相交,只要给 a_{i} 排序就行了。

②用标准的二分模板,计算当前的 mid 并用 check 函数检验当 D=mid 时是否有解。

③在 check 函数中分别记录当前已经安放好的奶牛数和上一头奶牛的位置,有个优化是可以直接计算一段草地能够安放的奶牛数

cnt=ceil((float)(g[i].r-g[i].l+1)/D) ④既然我们可以快速求出一个区间内最多安放的奶牛数,则只要通过前一个区间最后一个奶牛的位置加 $D$ 就可以求出这个区间第一个可安放奶牛的位置。只要把 $g[i].l$ 替换为 $next+D$ 即可算出当前区间的最多安放奶牛数。 注意当 $next+D\le g[i].l$ 时不用替换。 ⑤以此类推若此时已安放奶牛数大于 $N$ 就代表此时 $mid$ 可选,返回 $true$ 即可。 ⑥回到主函数中,若返回 $true$ ,则 $l=mid+1$,否则 $r=mid-1$ 。 ⑦当 $l>r$ 时,输出答案。 ------------ ### 代码 ```cpp #include<iostream> #include<stdio.h> #include<cstring> #include<string> #include<cmath> #include<algorithm> #include<vector> #include<map> #include<queue> #include<stack> #include<set> using namespace std; int n,m; struct node{ long long l,r; }g[100005]; bool cmp(node i,node j){ return i.l<j.l; } bool check(long long d){ long long cnt=ceil((float)(g[1].r-g[1].l+1)/d); long long next=g[1].l+d*(cnt-1); if(cnt>=n){ return true; } for(int i=2;i<=m;i++){ if(next+d>g[i].l){ long long tcnt=ceil((float)(g[i].r-next-d+1)/d); next=next+d+d*(tcnt-1); cnt+=tcnt; if(cnt>=n){ return true; } } else { long long tcnt=ceil((float)(g[i].r-g[i].l+1)/d); next=g[i].l+d*(tcnt-1); cnt+=tcnt; if(cnt>=n){ return true; } } } return false; } int main(){ cin>>n>>m; for(int i=1;i<=m;i++){ cin>>g[i].l>>g[i].r; } sort(g+1,g+m+1,cmp); long long l=0,r=g[m].r,ans; while(l<=r){ long long mid=(l+r)>>1; if(check(mid)){ ans=mid; l=mid+1; } else { r=mid-1; } } cout<<ans; return 0; } ```