码迷,mamicode.com
首页 > 其他好文 > 详细

CodeForces 343C Read Time 【二分答案】+【贪心】

时间:2018-09-20 17:20:56      阅读:204      评论:0      收藏:0      [点我收藏+]

标签:lan   net   记录   href   bre   第一个   style   http   直接   

<题目链接>

题目大意:

一条水平的磁道上有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

CodeForces 343C Read Time 【二分答案】+【贪心】

标签:lan   net   记录   href   bre   第一个   style   http   直接   

原文地址:https://www.cnblogs.com/00isok/p/9681668.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!