本文主要是介绍51nod 1521 一维战舰(二分),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
题目描述
爱丽丝和鲍博喜欢玩一维战舰的游戏。他们在一行有n个方格的纸上玩这个游戏(也就是1×n的表格)。
在游戏开始的时候,爱丽丝放k个战舰在这个表格中,并不把具体位置告诉鲍博。每一只战舰的形状是 1×a 的长方形(也就是说,战舰会占据a个连续的方格)。这些战舰不能相互重叠,也不能相接触。
然后鲍博会做一系列的点名。当他点到某个格子的时候,爱丽丝会告诉他那个格子是否被某只战舰占据。如果是,就说hit,否则就说miss。
但是这儿有一个问题!爱丽丝喜欢撒谎。他每次都会告诉鲍博miss。
请你帮助鲍博证明爱丽丝撒谎了,请找出哪一步之后爱丽丝肯定撒谎了。
Input
单组测试数据。
第一行有三个整数n,k和a(1≤n,k,a≤2*10^5),表示表格的大小,战舰的数目,还有战舰的大小。输入的n,k,a保证是能够在1×n的表格中放入k只大小为a的战舰,并且他们之间不重叠也不接触。
第二行是一个整数m(1≤m≤n),表示鲍博的点名次数。
第三行有m个不同的整数x1,x2,…,xm,xi是鲍博第i次点名的格子编号。格子从左到右按照1到n编号。
Output
输出一个整数,表示最早一次能够证明爱丽丝一定撒谎的点名编号。如果不能证明,输出-1。点名的编号依次从1到m编号。
Input示例
样例1
11 3 3
5
4 8 6 1 11
样例2
5 1 3
2
1 5
Output示例
样例输出1
3
样例输出2
-1
解题思路
将给定的点名二分查询,对于每一次查询,判断当前如果点名到了mid,其对应可放的战舰数与k之间的关系.并在处理过程中不断更新符合条件的最小值.
代码实现
#include<bits/stdc++.h>
using namespace std;
int n,k,len;
#define IO ios::sync_with_stdio(false);\
cin.tie(0);\
cout.tie(0);
#define INF 0x3f3f3f3f
const int maxn = 2e5+7;
int a[maxn],aa[maxn];
bool judge(int num)
{for(int i=1;i<=num;i++)aa[i]=a[i];sort(aa+1,aa+num+1);int cnt=0;int ll=1;for(int i=1;i<=num;i++){cnt+=(aa[i]-ll+1)/(len+1);ll=aa[i]+1;}cnt+=(n-ll+1+1)/(len+1);if(cnt>=k) return 1;return 0;}
int main()
{IO;cin>>n>>k>>len;int m;cin>>m;for(int i=1;i<=m;i++)cin>>a[i];int l=1,r=m;int ans= INF ;while(l<=r){int mid=(l+r)/2;if(judge(mid)) l=mid+1;else{r=mid-1;ans=min(ans,mid);}}if(ans==INF) cout<<"-1"<<endl;else cout<<ans<<endl;return 0;
}
这篇关于51nod 1521 一维战舰(二分)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!