题目的意思是:
如今有一个长度为n,宽为1的方格,在上面能够放大小为1*a船,然后输入为n,k,a。分别为平地的大小,船的数量,船的长度。
一个叫alice的人已经在地图上摆好了船的位置。
然后bob总共能够有m次攻击的机会,然后他每次攻击的点为xi。可是alice并不会告诉它有没有打中(也就是说每次都觉得他是miss的)。问你,bob能够在第几次攻击的时候猜測出alice在撒谎,假设猜測不出来则输出-1.
这里每两条相邻的船不能相互接壤。
思路:
用set来维护每一段的区间。
首先。我们最多能够放sum=(n+1)/(a+1)条船。
这个公式是怎么来的呢? 我们能够这样想: 由于船不能接壤。所以当有k条船时,n最少为k*(a+1)-1; 然后反解就能得到答案了。
然后我们每次攻击一个点t,就相当于把线段从中间隔开来了,我们要找到离点t近期的左右端点t1,t2,由于它们中间还插了一个t,所以就相当于t1,t2被切割开来了。
然后当前船的数量能够由还有一个公式得到: sum=sum-(t2-t1)/(a+1)+(t-t1)/(a+1)+(t2-t)/(a+1) ;这里的意思就相当于把原先的那个区间的部分减掉,然后再加上后来分开来后的区间所能容纳的船的最大数目。
当sum<k的时候,就说明此时alice在撒谎。
这里查找左右端点用的是二分查找。
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
using namespace std;
#define me rng_58
#define maxn 200055
set<int> st;
set<int>::iterator it;
int main(){
int n,k,a,m,i;
scanf("%d%d%d",&n,&k,&a);
scanf("%d",&m);
st.insert(0);
st.insert(n+1);
int sum=(n+1)/(a+1);
int ans=-1;
for(i=1;i<=m;i++){
int t;
scanf("%d",&t);
it=st.upper_bound(t);
int t1=*it;
it--; //这里为什么能减。学c++后再解答;
int t2=*it;
st.insert(t); //这里仅仅要把t压进去就好啦!!
!小心!。!
sum=sum-(t1-t2)/(a+1)+(t-t2)/(a+1)+(t1-t)/(a+1); if(sum<k){ ans=i; break; } } printf("%d\n",ans); } /* 5000 1660 2 20 1 100 18 102 300 81 19 25 44 88 1337 4999 1054 1203 91 16 164 914 1419 1487 */
佩服那些可以想出来的人。Wish I can become the same like U one day!