Codeforces 567D - One-Dimensional Battle Ships - [樹狀數組+二分]

題目連接:https://codeforces.com/problemset/problem/567/Dc++

 

題意:數組

在一個 $1 \times n$ 的網格上,初始擺放着 $k$ 只船,每隻船的長度均爲 $a$ 個格子,已知全部船之間均不重疊、不觸碰。spa

如今Bob每次詢問Alice第 $i$ 個格子上是否存在船,Alice每次都會說不存在,求在第幾回詢問時,能夠肯定Alice撒謊了。code

 

題解:blog

對於某次詢問一個位置 $x$ 是否有船,假設其屬於某個最小的區間 $(l,r)$,其中 $l,r$ 分別是曾經詢問過的位置。咱們用樹狀數組配合二分 $O(\log^2 n)$ 尋找出 $l,r$。ci

那麼,能夠計算出,$(l,r)$ 區間曾經最多能停放多少船隻,而如今變成了兩個區間 $(l,x)$ 和 $(x,r)$ 後,又能停放多少船隻。get

這樣一來,最開始咱們計算出整個區域 $(0,n+1)$ 最多放多少船隻 $cur$,進而對每次計算都能計算出減小了多少船隻,即 $cur$ 會減去一個數,直到某一次詢問,使得 $cur<k$,即表明Alice撒謊了。it

 

AC代碼:class

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int n,k,a,m;

struct _BIT
{
    int N,C[maxn];
    #define lowbit(x) (x&(-x))
    void init(int n) //初始化共有n個點
    {
        N=n;
        for(int i=1;i<=N;i++) C[i]=0;
    }
    void add(int pos,int val) //在pos點加上val
    {
        while(pos<=N)
        {
            C[pos]+=val;
            pos+=lowbit(pos);
        }
    }
    int ask(int pos) //查詢1~pos點的和
    {
        int ret=0;
        while(pos>0)
        {
            ret+=C[pos];
            pos-=lowbit(pos);
        }
        return ret;
    }
}BIT;

int lower(int x)
{
    int l=1, r=BIT.N;
    while(l<r)
    {
        int mid=(l+r)>>1;
        if(BIT.ask(mid)<x) l=mid+1;
        else r=mid;
    }
    return l;
}

int upper(int x)
{
    int l=1, r=BIT.N;
    while(l<r)
    {
        int mid=(l+r)>>1;
        if(BIT.ask(mid)<=x) l=mid+1;
        else r=mid;
    }
    return l;
}

int main()
{
    cin>>n>>k>>a>>m;

    BIT.init(n+2);
    BIT.add(1,1), BIT.add(n+2,1);
    int cur=(n+1)/(a+1);
    for(int i=1,x;i<=m;i++)
    {
        scanf("%d",&x), x++;

        int tp=BIT.ask(x);
        int l=lower(tp), r=upper(tp);
        int old=(r-l)/(a+1);
        int now=(r-x)/(a+1)+(x-l)/(a+1);
        cur-=old-now;

        if(cur<k)
        {
            printf("%d\n",i);
            return 0;
        }

        BIT.add(x,1);
    }
    printf("-1\n");
}
相關文章
相關標籤/搜索