题意:
爱丽丝和鲍博喜欢玩一维战舰的游戏。他们在一行有n个方格的纸上玩这个游戏(也就是1×n的表格)。
在游戏开始的时候,爱丽丝放k个战舰在这个表格中,并不把具体位置告诉鲍博。每一只战舰的形状是 1×a 的长方形(也就是说,战舰会占据a个连续的方格)。这些战舰不能相互重叠,也不能相接触。
然后鲍博会做一系列的点名。当他点到某个格子的时候,爱丽丝会告诉他那个格子是否被某只战舰占据。如果是,就说hit,否则就说miss。
但是这儿有一个问题!爱丽丝喜欢撒谎。他每次都会告诉鲍博miss。
请你帮助鲍博证明爱丽丝撒谎了,请找出哪一步之后爱丽丝肯定撒谎了。
思路:
利用set保存各个miss点的位置,另外用cnt保存当前格子中最多能存放几个战舰,每次询问一个新的点pos,都利用二分找到这个点左右两边的第一个点l,r,这样就可以计算出增加了pos这个点前后cnt损失了多少,如果cnt < k了就输出当前询问编号,否则将pos也插入set。
一开始看错题了,没看到战舰也不能接触,所以一段长度为len的连续区间内最多能放(len+1)/(a+1)艘战舰。
代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 10;
int q[MAXN];
set <int> :: iterator it;
int main() {
int n, m, k, a;
scanf("%d%d%d%d", &n, &k, &a, &m);
for (int i = 1; i <= m; i++)
scanf("%d", &q[i]);
set <int> st;
int cnt = (n + 1) / (a + 1);
st.insert(0); st.insert(n + 1);
for (int i = 1; i <= m; i++) {
if (st.find(q[i]) != st.end()) continue;
it = st.upper_bound(q[i]);
int r = *it, l = *(--it);
// printf("%d %d\n", l, r);
int t1 = (r - l) / (a + 1), t2 = (r - q[i]) / (a + 1) + (q[i] - l) / (a + 1);
cnt -= (t1 - t2);
// cout << cnt << endl;
if (cnt < k) {
printf("%d\n", i);
return 0;
}
st.insert(q[i]);
}
puts("-1");
return 0;
}