<题目链接>
题目大意:
一条水平的磁道上有n个磁头和m个待扫描的点,磁头可以左右互不干扰的移动去扫描点,每秒移动一个单位(也可以停留在原地),求这些磁头扫描完这些所有的点最少需要要花多少时间。
解题分析:
本题用二分答案和贪心求解,先二分出这些磁头扫描完所有的点所需的时间,然后用贪心策略去模拟每个磁头扫描这些点。对这些磁头从左向右分析,假设二分出的总时间为mid,在该条件下,每个磁头扫描点的最优情况毫无疑问是,在保证扫描到当前 最左边未被扫描到的点的情况下,向右扫描尽可能远的距离(对于这些磁头从左向右分析时)。但是同时,有几种情况要讨论:1.如果最左边的为扫描过的点在该磁头的右侧,那么该磁头在mid时间内全部向右移动即可;2.如果最左边的点在当前磁头的左侧,如果到达不了最左边未走过的点,那么说明mid枚举过小,重新枚举。如果能够到达这个最左边的未被扫描过的点,也要分两种情况:一是,磁头先向左走,在能够到达最左边未走过的点的情况下,记录它向右到达的最远距离。二是,该磁头开始先向右走,在当前枚举的mid范围下,在保证经过最左边的那个点的情况下,尽量向右走的更远。至于为什么磁头开始走的方向也要分情况讨论,可以参照一下样例三。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const int M =1e5+5; int n,m,vis[M]; ll h[M],p[M]; int main(){ while(scanf("%d%d",&n,&m)!=EOF){ for(int i=1;i<=n;i++)scanf("%lld",&h[i]); for(int i=1;i<=m;i++)scanf("%lld",&p[i]); ll maxn; if(h[1]<p[1])maxn=p[m]-h[1]; else{ maxn=h[1]-p[1]; if(h[1]<p[m]){ maxn=min(2*maxn+p[m]-h[1],maxn+2*(p[m]-h[1])); //第一个探头先向左走和向右走,走完所有触点的总时间,从这两个总时间中取最小的作为二分答案的上界;注意,取最小的作为上界,因为如果只有一个探头,那么算出来的结果直接就是答案,如果有多个探头,第一个探头走完所有触点的最短时间也足以作为上界 } } ll l=0,r=maxn; while(l<r){ memset(vis,0,sizeof(vis)); //标记每个触点是否走过 ll mid=(l+r)>>1; //二分答案,mid为这些探头经过所有的触点所需的时间 ll dist=0;int loc,k; for(int i=loc=1;i<=n;i++){ if(p[loc]>=h[i]) //最左边的没有走过的触点 dist=mid+h[i]; else{ if(h[i]-p[loc]>mid)break; dist=max(h[i]+mid-2*(h[i]-p[loc]),h[i]+(mid-(h[i]-p[loc]))/2); //在枚举的答案下,即总共花费的时间下,该探头在能够在 走过最左边没有走过的触点的情况下,尽可能的向右走的更远 } for(k=loc;p[k]<=dist&&k<=m;k++)vis[k]=1; //将新走过的触点标记 if(vis[m])break; //如果最后一个触点都被标记了,就跳出 else loc=k; } if(vis[m])r=mid; else l=mid+1; } printf("%lld\n",l); } return 0; }
2018-09-20
原文地址:https://www.cnblogs.com/00isok/p/9681668.html
时间: 2024-11-08 23:52:58