codeforces 314 D One-Dimensional Battle Ships (模拟)

本文介绍了一种在一维战舰游戏中检测玩家作弊的方法。通过跟踪玩家射击位置及更新可放置船只数量来判断是否存在欺骗行为。具体实现利用了set数据结构辅助查找未射击区域的边界。
D. One-Dimensional Battle Ships
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Alice and Bob love playing one-dimensional battle ships. They play on the field in the form of a line consisting of nsquare cells (that is, on a 1 × n table).

At the beginning of the game Alice puts k ships on the field without telling their positions to Bob. Each ship looks as a1 × a rectangle (that is, it occupies a sequence of a consecutive squares of the field). The ships cannot intersect and even touch each other.

After that Bob makes a sequence of "shots". He names cells of the field and Alice either says that the cell is empty ("miss"), or that the cell belongs to some ship ("hit").

But here's the problem! Alice like to cheat. May be that is why she responds to each Bob's move with a "miss".

Help Bob catch Alice cheating — find Bob's first move, such that after it you can be sure that Alice cheated.

Input

The first line of the input contains three integers: nk and a (1 ≤ n, k, a ≤ 2·105) — the size of the field, the number of the ships and the size of each ship. It is guaranteed that the nk and a are such that you can put k ships of size aon the field, so that no two ships intersect or touch each other.

The second line contains integer m (1 ≤ m ≤ n) — the number of Bob's moves.

The third line contains m distinct integers x1, x2, ..., xm, where xi is the number of the cell where Bob made the i-th shot. The cells are numbered from left to right from 1 to n.

Output

Print a single integer — the number of such Bob's first move, after which you can be sure that Alice lied. Bob's moves are numbered from 1 to m in the order the were made. If the sought move doesn't exist, then print "-1".

Sample test(s)
input
11 3 3
5
4 8 6 1 11
output
3
input
5 1 3
2
1 5
output
-1
input
5 1 3
1
3
output
1

比赛的时候没搞出来,really sad.
其实这题很容易啊....
首先,对于lie 的判断应该基于能放的船的个数.
能放的船的个数是随着射的点数的增加而减少的.
射完每个点后更新能放的船的个数,如果这个时候已经无法放下k条船了,说明lie了.
如果所有都射完也没发生,那么就-1.

由于船与串不能相邻,除了最后一条船,每条船实际占的size 应该为a+1
那么很容易知道对于长度为l的区间,能放的船的个数为(l+1)/(a+1)
这是初始能放的船的个数,为最大值.
当射了点b之后,破坏的是b所在的一段最大的没有被射过点的区间的连续性.
做法是找到距离b点最近的左端和右端的被射过的点.
可以用set 搞,找的时候upper_bound
记得初始化的时候把 0点和 n+1 点当成射过的.
/*************************************************************************
    > File Name: code/cf/#314/D.cpp
    > Author: 111qqz
    > Email: rkz2013@126.com 
    > Created Time: 2015年08月16日 星期日 00时27分54秒
 ************************************************************************/

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<map>
#include<set>
#include<queue>
#include<vector>
#include<stack>
#define y0 abc111qqz
#define y1 hust111qqz
#define yn hez111qqz
#define j1 cute111qqz
#define tm crazy111qqz
#define lr dying111qqz
using namespace std;
#define REP(i, n) for (int i=0;i<int(n);++i)  
typedef long long LL;
typedef unsigned long long ULL;
const int inf = 0x7fffffff;
set<int> se;
int n,k,a,m,b;
set<int>::iterator it;
int cal (int x,int y)  //cal 函数计算出当射了b之后,因此减少的能放船的个数.
{
    int res;
    res = (y-x)/(a+1)-(y-b)/(a+1)-(b-x)/(a+1);//由于射了b点,相当于之前连续的区间(x,y)被分成了(x,b)和(b,y)
                          //(x,y)区间能放的船的数量由之前变成了被分成的两个小区间能放的船的数量的和.                    
    return res;
}
int main()
{
    scanf("%d %d %d",&n,&k,&a);
    scanf("%d",&m);
    se.clear();
    int sum=(n+1)/(a+1); //sum表示的是当前能放的船的个数
                //容易知道,对于长度为l的点,最多能放的船的数量为(l+1)/(a+1);
    se.insert(0);
    se.insert(n+1);//由于要找要被射的点两遍最近的被射的点,我们不妨认为0点和n+1点也是被射的,这样处理断点容易些.
    int ans = -1;
    bool flag = false;
    for (int i=1;i<=m;i++)
    {
        scanf("%d",&b);
        if (flag) continue;
        it=se.upper_bound(b);
        int y=*it;
        int x=*(--it);   //y和x分别是离b点最近且已经被射的点
        sum = sum - cal(x,y);
        if (sum<k)
        {
        ans =  i;
        flag = true;
        }
        se.insert(b);
    }
    cout<<ans<<endl;
    return 0;
}

 

转载于:https://www.cnblogs.com/111qqz/p/4733486.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值