题目的意思是:
如今有一个长度为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 ",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!