codeforces 343c Read Time

原题连接:http://codeforces.com/contest/344/problem/E
题意:
一条水平的磁道上有n个磁头和m个待扫描的点,磁头可以左右互不干扰的移动去扫描点,每秒移动一个单位,求最少要花多少时间;

解法(贪心+二分查找):
从整个磁道的最左端的待扫描的点开始,如果该区域点左端没有磁头,那么一定是离该点右端的第一个磁头去扫描它,找到一个最小需要的时间len, 在保证可以扫到最左端的第一个能被扫到的情况下,该磁头能向右走多远就走多远,这样就可以扫到更多的点(贪心)。如果该点左边有磁头,那么先判断该磁头可否扫到改点,不行再用右边的磁头去扫,这样可以保证右边的磁头向右走的比较远,然后找到一个最小的时间len,进行二分搜索判断,就可以以了

下面是codeforces上面的题解
这里写图片描述
大意为:先确定一个时间t进行二分查找,如果第一个磁头h[0]>最左端的待扫描点p[0],那么直接向右边走ts,否则的话会存在两种情况,在时间t内,先向右走,在折返回到左边,或者是先向左走,利用剩余的时间,向右走(向右越远,扫描的磁头越多),比较哪种可以向右边走的比较远,选哪种,(最左端那个一定需要被该磁头扫的),然后会出现图片的那几条公式判断两种走法的距离,然后不断的更新最左端的待扫点直到最后看所有磁头扫完的时候,判断所有扫描点是否被扫完,就能判断在t时间内能不能完成扫描。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
using namespace std;
const __int64 maxn=100050;
__int64 h[maxn],p[maxn],vis[maxn];

int main()
{
    __int64 n,m,i,j,cj,len,mid,l,r,dest;
    scanf("%I64d%I64d",&n,&m);
    for(i=0;i<n;i++)
        scanf("%I64d",&h[i]);
    for(i=0;i<m;i++)
        scanf("%I64d",&p[i]);
    //先随机取一个磁头,确定该磁头扫描整个磁道要花的时间,以此为最少时间
    if(h[0]<p[0])
        len=p[m-1]-h[0];
    else
    {
        len=h[0]-p[0];
        if(h[0]<p[m-1])
            len=min(len*2+p[m-1]-h[0],len+2*(p[m-1]-h[0]));
    }

    l=0,r=len;
    int flag;
    while(l<r)
    {
        mid=(l+r)>>1;
        memset(vis,0,sizeof(vis));
        for(i=cj=0;i<n;i++)//按照磁头从左到右的顺序,把磁头可以扫描的点扫描记录
        {
            if(h[i]<=p[cj])//如果当前最左边未被扫描的点在当前的磁头的右边
                dest=h[i]+mid;
            else//在左边
            {
                if(mid<(h[i]-p[cj])) 
                    break;//如果该磁头无法到达左边没有扫描过的点,直接跳出
                dest=max(p[cj]+mid-(h[i]-p[cj]),h[i]+(mid-(h[i]-p[cj]))/2); //先向左走和先向右走,看哪种走的右边比较远
            }
            for(j=cj;p[j]<=dest && j<m ;j++)//将扫描过的点记录
                vis[j]=1;
            if(vis[m-1])//全部区域扫描完成,结束
                break;
            cj=j;//还没扫描完,记录下当前最左边未被扫描的点位置
        }
        if(vis[m-1])//判断是否扫描完毕,继续二分搜索
            r=mid;
        else
            l=mid+1;
    }
    printf("%I64d\n",l);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值