1. 程式人生 > >【NOIP模擬10-21】的士碰撞

【NOIP模擬10-21】的士碰撞

min urn cmp dir cnblogs struct noip 開始 format

Description

??輛車在一條數軸上,車的編號為1到??。編號為??的車坐標為??[??],初始方 向為??????[??](左或右),初始位置兩兩不同。每輛車每個時刻行走距離為1。兩輛 車相碰時,會調轉方向,繼續行走,掉頭不消耗時間。現在車子開始朝其方向行 駛,同一個坐標允許有多輛車。現在有??個詢問,給出??, ??,詢問過了??時刻後, 編號為??的車的坐標的絕對值。

Input Format

輸入文件名為collision.in。 首先輸入??, ??。 接下來??行,每行兩個整數??[??], ??????[??],若??????[??] = 0,表示車子向左行走,若 ??????[??] = 1,表示車子向右行走。 接下來??行,每行兩個整數??, ??,詢問時刻??時編號為??的車的坐標。

Output Format

輸出文件名為collision.out。 對於每個詢問,輸出一個整數,代表編號為??的車的坐標。

Sample Input & Sample Output

【輸入輸出樣例1】 collision.in collision.out 5 5 1 1 4 1 2 0 7 1 11 0 5 1 10 2 7 3 8 4 20 5 3 1 8 12 27

【輸入輸出樣例2】 collision.in collision.out 20 15 31116973 1 721410312 0 152891538 1 55434456 0 903968 1 34492580 0 97565125 0 78559065 1 191708700 0 335941230 0 526621966 1 25622049 38331852 977130985 662422758 171848754 220003868 5474029 533404717 11069472 1056101384 524968026 326917138168159348 1 457798506 1 160026937 1 76511872 1 247171016 1 48722268 0 159552820 0 701333640 0 434868520 1 143857480 13 821356724 11 132436670 1 20249229 11 504666 16 138701034 19 339607872 1 184664000 13 80827802 15 625365533 5 668115287 6 93821572 7 175176488 5 438184710 1 71279702 12 237940668 420617936 689224277

Hint

【數據規模與約定】 對於30%的數據,max(??) ×?? ≤ 107 另外有30%的數據,??, ?? ≤ 1000 對於100%的數據,??, ?? ≤ 100000,0 ≤ ??[??] ≤ 109 ,?? ≤ 109 , ??????[??] ∈ {0,1}

思路

首先的士碰撞之後會掉頭,
在這裏我們可以理解為兩輛車互換了編號,
然後繼續前行。
那如何求出編號為x的最終位置呢?
這裏可以用二分答案,
要用二分,我們需要單調。
因為在坐標軸上,從小到大,很顯然是單調的。
如何驗證答案,

技術分享
如圖,我們可以發現箭頭變大了一輛車的rank是不會改變的,

因為大家的速度是一致的,不存在追及,而且相遇後會掉頭,
所以它會一直在原來位置的前一輛車和後一輛車中間。
我們把車按照位置排一次序,
然後我們二分一個位置,使這個位置的rank與原來的相等;
詢問這個位置的rank直接for循環一遍會超時,
所以我們繼續二分,先按照方向和位置,把車分成A、B兩組,
分別表示向右走和向左走的車的原始位置。
然後分別二分找出A中與B中比X小的車數量,兩者相加就是X的rank,即可驗證答案.

#include<cstdio>
#include<algorithm>
#define LL long long

int n,q,tota,totb;
LL a[100005],b[100005];
struct node
{
    int pos,rank,num;
}nod[100005];

bool cmp(node x,node y)
{
    return x.pos<y.pos;
}

int Count(LL a[],int len,LL x)
{
    int res=0,l=1,r=len;
    while (l<=r)
    {
        int mid=(l+r)>>1;
        if (a[mid]<=x) res=mid,l=mid+1;
        else r=mid-1;
    }
    return res;
}

int main()
{
    scanf("%d%d",&n,&q);
    for (int i=1;i<=n;i++)
    {
        int dir;
        scanf("%d%d",&nod[i].pos,&dir);
        nod[i].num=i;
        if (dir) a[++tota]=nod[i].pos;
        else b[++totb]=nod[i].pos;
    }
    std::sort(nod+1,nod+n+1,cmp);
    for (int i=1;i<=n;i++) nod[nod[i].num].rank=i;    
    std::sort(a+1,a+tota+1);
    std::sort(b+1,b+totb+1);
    for (int i=1;i<=q;i++)
    {
        int tim,num,ans=0;
        scanf("%d%d",&tim,&num);
        num=nod[num].rank;
        LL l=std::min(a[1]+tim,b[1]-tim),r=std::max(a[tota]+tim,b[totb]-tim);
        while (l<=r)
        {
            LL mid=(l+r)>>1;
            int count=Count(a,tota,mid-tim)+Count(b,totb,mid+tim);
            if (count>=num) ans=mid,r=mid-1;
            else l=mid+1;
        }
        printf("%d\n",abs(ans));
    }
}

【NOIP模擬10-21】的士碰撞