zoukankan      html  css  js  c++  java
  • Codeforces 567D One-Dimensional Battle Ships

    传送门

    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 n square 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 a 1 × 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 putk ships of size a on 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

    --------------------------------------------------------------------------------------------------

    比赛时很快想到解法,之后意识到要用线段树维护,但我对线段树还不是特别熟练,没写出来,想想十分可惜。

    Solution

    任意时刻Alice可以放置ship的地方是一些区间(线段)(active segments),我们设法维护这些区间,需支持下列操作:

    1. 查询某个cell所在的区间

    2. 将某个区间分成多个区间

    根据Bob每次guess的结果维护Alice的active segments,计算出Alice当前最多能放几个ship,若果小于k,则可断言Alice说谎了。

    ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    #include<bits/stdc++.h>
    using namespace std;
    const int MAX_N=2e5+10;
    int tag[MAX_N<<2];
    int ma[MAX_N<<2];
    typedef pair<int,int> P;
    P query(int id, int L, int R, int val){
    	if(tag[id]) return P(L, tag[id]);
    	int mid=(L+R)>>1;
    	if(ma[id<<1]>=val)
    		return query(id<<1, L, mid, val);
    	return query(id<<1|1, mid+1, R, val);
    }
    void insert(int id, int L, int R, int l, int r, int val){
    	if(l>r) return;
    	if(l<=L&&R<=r) tag[id]=ma[id]=val;
    	else{
    		int ls=id<<1, rs=ls|1, mid=(L+R)>>1;
    		if(tag[id]){
    			tag[ls]=ma[rs]=tag[id];	//error-prone
    			tag[rs]=ma[rs]=tag[id];
    			tag[id]=0;
    		}
    		if(l<=mid)
    			insert(ls, L, mid, l, r, val);
    		if(r>mid)
    			insert(rs, mid+1, R, l, r, val);
    		ma[id]=max(ma[ls], ma[rs]);
    	}
    }
    int n, k, a, m, g, now;
    int cap(int len){return (len+1)/(a+1);}
    void init(){
    	scanf("%d%d%d%d", &n, &k, &a, &m);
    	tag[1]=ma[1]=n;
    	now=cap(n);
    }
    #define X first
    #define Y second
    int main(){
    	freopen("in", "r", stdin);
    	init();
    	P seg;
    	int ans=-1;
    	for(int i=1; i<=m; i++){
    		scanf("%d", &g);
    		//printf("g: %d
    ", g);
    		seg=query(1, 1, n, g);
    		//printf("%d %d
    ", seg.X, seg.Y);
    		now-=cap(seg.Y-seg.X+1);
    		now+=cap(g-seg.X);
    		now+=cap(seg.Y-g);
    		//printf("%d
    ", now);
    		if(now<k){
    			ans=i;
    			break;
    		}
    		insert(1, 1, n, seg.X, g-1, g-1);
    		insert(1, 1, n, g, g, g);
    	}
    	printf("%d
    ", ans);
    }
    

     P.S. 这道题再次写复杂了,我的解法是一种模拟解法,线段树只是起到加速的作用,并不是算法的核心。

    我的算法是:模拟Bob的猜测过程,每猜一次就判断当前能否放得下k条船。但如果裸模拟的话可能会T。

    这道题比较简单的解法是二分答案,然后再O(n)判断。

    当时我完全没想到可O(n)判断,当然也没想到二分答案(这可是赤裸裸的二分答案题啊),

    二分答案的复杂度是严格的O(n log m),我的写法的复杂度还依赖于答案的大小,最坏情况复杂度是O(m log n)。

    ——————————————————————————————————————————————————————

    现在头脑越来越不灵了T^T。

  • 相关阅读:
    [na]ip数据包格式
    [js]浏览器同源策略(same-origin policy)
    [sql] 同库表(结构)的备份和sql聚合&navicat使用
    [svc]tcp三次握手四次挥手&tcp的11种状态(半连接)&tcp的time-wait
    [svc]ip地址划分
    [css]单/多行居中&字体设置
    时间戳转为C#格式时间
    windows 8 中 使用 httpclient
    oralce 查看是否启动 登陆 创建用户 常用命令小记
    SQL递归查询(with cte as)
  • 原文地址:https://www.cnblogs.com/Patt/p/4709663.html
Copyright © 2011-2022 走看看