• 2018.11.03-dtoj-2910-独木桥(bridge)


    题目描述:

    Alice和Bob是好朋友,这天他们带了n个孩子一起走独木桥。

    独木桥宽度很窄,不允许两个或两个以上的人并肩行走,所有人必须要前后一个接一个地通行。

    Bob给所有的孩子蒙上了眼,并将他们放在桥中不同的位置上,孩子们初始的朝向不一定相同。Bob吹响哨声后这些孩子们会按照初始的朝向开始移动,当两个孩子移动到同一点时由于桥太窄他们无法穿过彼此,因此他们会同时转身改变朝向,并接着朝新方向移动。

    为了安全起见,在某个时刻Alice会询问Bob某个孩子现在所处的位置。

    更具体的,我们可以将问题抽象如下:

    · 将独木桥看作一个长度无限长的实数轴,将每个孩子看作数轴上的一个实数点。数轴从左到右坐标不断增大。

    · 孩子的位置用相对于数轴原点的点的坐标来表示。初始时n个点在n个互不相同的整点上。

    · 每个点有一个初始朝向(从左向右或从右向左)。任何时刻所有的点都会以每秒1单位长度的速度匀速向所朝的方向移动。当某个时刻两个点同时移动到了同一个位置上,它们会立即改变自己的朝向(从左向右变成从右向左,反之亦然),然后继续移动。

    ·有q次询问,每次询问给定ki与ti,询问在ti秒后,孩子ki目前的位置。

    Bob无法同时关注这么多的孩子,请你帮帮他。

    输入:

    第一行一个整数n表示孩子数,孩子从0开始编号。

    第二行n个整数pi,表示孩子们的初始位置。

    第三行n个整数di,表示孩子们的初始朝向。di=0则初始向左,di=1则初始向右。

    第四行一个整数q 表示询问数。

    接下来q行每行两个整数ki,ti表示一个询问,询问在titi秒

    后,孩子ki (按输入顺序)目前的位置。

    输出:

    输出q行每行一个整数表示答案。

    数据范围:

    20%的数据:n,pi,ti≤10n,

    另有20%的数据:di均相同

    另有20%的数据:q≤10

    另有15%的数据:ti≤100

    另有15%的数据:n≤1000

    1OO%的数据:1≤n,q≤2∗105  0≤ki<n 0≤pi,ti≤109 di∈0,1

     算法标签:二分

    思路:

    这题的简单版是蚂蚁,妙的地方在于两个孩子相撞继续走,其实相当于像个孩子交换编号继续不改方向的前行,所以其实最后有孩子的位置就是按原方向向前t的坐标,至于每个孩子的位置在哪,由于每个孩子的排名始终不改变,即一个孩子的左右孩子的个数始终不变。所以我们可以把两个方向的孩子放在两个不同数组里,每次二分一个答案坐标,然后求出这个左边的排名,效率是O(n*logn*log1e9)。

    另一个nlogn的算法相对难写,似乎是用线段树维护。

    以下代码:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #define re register
    #define il inline
    #define LL long long
    #define _(d) while(d(isdigit(ch=getchar())))
    using namespace std;
    const int N=2e5+5,inf=2e9;
    int n,tot1,tot2,pos[N];struct node{int p,id,d;}t[N];int q1[N],q2[N];
    il int read(){int x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch^48;_()x=(x<<1)+(x<<3)+(ch^48);return f*x;}
    bool cmp(node t1,node t2){return t1.p<t2.p;}
    int pd(LL x,int t){
        int res1,res2;
        res1=upper_bound(q1+1,q1+1+tot1,x-t)-q1;res1--;
        res2=upper_bound(q2+1,q2+1+tot2,x+t)-q2;res2--;
        return res1+res2;
    }
    int main()
    {
        n=read();for(re int i=1;i<=n;i++){
            t[i].p=read();t[i].id=i;
        }
        for(re int i=1;i<=n;i++)t[i].d=read();
        sort(t+1,t+1+n,cmp);
        for(re int i=1;i<=n;i++)pos[t[i].id]=i;
        for(re int i=1;i<=n;i++){
            if(t[i].d==0)q2[++tot2]=t[i].p;
            else q1[++tot1]=t[i].p;
        }
        int Q=read();while(Q--){
            int k=pos[read()+1],tt=read();
            int l=t[1].p-tt,r=t[n].p+tt,res;res=r;
            while(l<=r){
                LL mid=(((LL)l+(LL)r)>>1ll);
                if(pd(mid,tt)>=k)res=mid,r=mid-1;else l=mid+1;
            }
            printf("%d
    ",res);
        }
      return 0;
    }
    View Code
  • 相关阅读:
    php 信号量
    .net 反射初体验
    IEnumerable,IQueryable之前世今生
    [SQL]511+512+534+550+569
    [SQL]183+184+185+196+197
    [SQL]3.26--175+176+177+178+180+181+182
    [剑指offer]10.斐波那契数列+青蛙跳台阶问题
    [剑指offer]14-1.剪绳子
    [剑指offer]62.圆圈中最后剩下的数字
    [剑指offer]52.两个链表的第一个公共节点
  • 原文地址:https://www.cnblogs.com/Jessie-/p/9901275.html
Copyright © 2020-2023  润新知