【题意】Bob和Alice在玩一个游戏,在一个长度为n的河上,Alice放了k艘长度为a的船,每艘船之间不能相交,且两艘船之间不能相邻(即1~3,4~6是不允许的),Bob不知道船放在哪,于是他向Alice询问了m个位置是否有船,Alice都回答了没有船,问Alice是否在撒谎。如果撒谎了求出最早第几次询问能确定Alice在撒谎。
【分析】就是给出一个空白区间,依次删除m个点,问剩余的连续段能放几艘船,把删除掉的点放入set,每次删除一个点时二分查最靠近该点的被删除的点,即可确定当前段的长度,删掉这段区间能放的船数量,加上被该点分成的新的两段的能放船的数量,当能放的船小于k时,Alice撒谎了。关键是对于计算区间长度为len时能放的船的数量(我就是没想到这个),其实很简单,就是(len+1)/(a+1);
【AC CODE】124ms
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,n) for(int i = a; i < n; i++)
#define repe(i,a,n) for(int i = a; i <= n; i++)
#define per(i,n,a) for(int i = n; i >= a; i--)
#define clc(a,b) memset(a,b,sizeof(a))
const int INF = 0x3f3f3f3f, MAXN = 200000+10;
int a[MAXN],n,k,s,m;
set<int> vis;
inline int get_sum(int len){ return (len+1)/(s+1);}
int sloved()
{
int cnt = get_sum(n);
vis.insert(0),vis.insert(n+1);
repe(i,1,m)
{
auto it = vis.lower_bound(a[i]);
int ed = *it;
if(ed == a[i]) continue;
it--;
int st = *it;
int len =ed-st-1;
vis.insert(a[i]);
if(len < s) continue;
cnt -= get_sum(len);
cnt += get_sum(a[i]-st-1)+get_sum(ed-a[i]-1);
if(cnt < k) return i;
}
return -1;
}
int main()
{
#ifdef SHY
freopen("d:\\1.txt", "r", stdin);
#endif
scanf("%d %d %d %d", &n, &k, &s, &m);
repe(i,1,m) scanf("%d", &a[i]);
printf("%d\n",sloved());
return 0;
}