51nod 1521 一維戰艦+set+二分
阿新 • • 發佈:2018-11-17
題目連結:
一行有n個方格的紙上,愛麗絲放k個戰艦在這個表格中,並不把具體位置告訴鮑博。每一隻戰艦的形狀是 1×a 的長方形(也就是說,戰艦會佔據a個連續的方格)。這些戰艦不能相互重疊,也不能相接觸。然後鮑博會做一系列的點名。當他點到某個格子的時候,愛麗絲會告訴他那個格子是否被某隻戰艦佔據。如果是,就說hit,否則就說miss。但是這兒有一個問題!愛麗絲喜歡撒謊。他每次都會告訴鮑博miss。請你幫助鮑博證明愛麗絲撒謊了,請找出哪一步之後愛麗絲肯定撒謊了。如果不能證明輸出-1。
第一行有三個整數n,k和a。
第二行是一個整數m(1≤m≤n),表示鮑博的點名次數。
第三行有m個不同的整數x1,x2,…,xm,xi是鮑博第i次點名的格子編號。格子從左到右按照1到n編號。
思路:這道題當時想的是計算浪費的空間,當浪費的空間使得空間放不下戰艦為止。但是計算過的區間要標記,但是戰艦的位置不確定,所以區間無法標記。
然後也想了二分,計算能放下戰艦的最大數量,當最大數量<k就證明愛麗絲撒謊了。但是也感覺無法維護。。。。。
看了題解,就是二分。。。。
因為每個戰艦不能相接觸,我們可以把每次詢問x;相當在x空格插入一堵牆(開始插入0, n+1)。並把這個區間一分為二。ans=ans-之前這個區間能放下的最大數量+(左區間能放下的最大數量+右區間能放下的最大數量)
那麼第一種思路也能維護浪費的空間:ans=ans-之前這個區間浪費的空間+(左區間浪費的空間+右區間浪費的空間)
思考:當時還在想是不是考慮這個區間是不是最左最右區間,因為這樣可以可以放最左邊或最右邊。也考慮每次詢問是否相同。該用multiset還是set。
後來引入牆就發現,每次詢問都是同一種過程,而且詢問相同就是在之前有牆的地方放牆,什麼也沒有改變。
#include <bits/stdc++.h> using namespace std; set<int> s; int main() { int n, k, a, m, ans; scanf("%d%d%d",&n,&k,&a); ans=(n+1)/(a+1); s.insert(0); s.insert(n+1); scanf("%d",&m); int p=0; for(int i=1;i<=m;i++) { int f, l, r; scanf("%d",&f); l=*(--s.lower_bound(f));//區間左邊的牆 r=*(s.upper_bound(f));//區間右邊的牆 ans-=(r-l)/(a+1);//減去之前這個區間能放下的最大數量 ans+=(f-l)/(a+1)+(r-f)/(a+1);//加上左區間能放下的最大數量+右區間能放下的最大數量 s.insert(f);//插入牆 if(ans<k&&p==0) p=1, cout<<i<<endl; } if(!p) cout<<-1<<endl; return 0; }