题目的意思是:
现在有一个长度为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!
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-13 05:27:41