[51Nod] (1521) 一维战舰 ---- 思维+二分

版权声明:本文为博主原创文章,转载请预先通知博主(〃▽〃)。 https://blog.csdn.net/m0_37624640/article/details/84071317

题目传送门

思路:

  • 看了一大会儿没有思路,这类区间问题确实很需要想象力!QAQ 我发现这类算法题,我不由自主地给它做加法,从而导致思维混乱(痛苦阴影
  • 其实这类题目,要给它做减法。 我们每查询一个编号所对应的方格,一定控制着某段区间,这段区间必被视为不可用。
  • 如果它不合法,一定是因为它在所有情况下都必被战舰覆盖。除了它占用的空间外,那么剩余的区间如果不能放的下k个战舰,那么证明此次查询一定不合法。
  • 如果它合法,除了它占用的空间外,那么剩余的区间如果能放的下k个战舰,那么证明此次查询一定合法。
  • 基于这种逆向思维。做减法,首先我们可以推出整个区间最多放cnt = (n+1)/(a+1) 个战舰,注意:战舰之间不能覆盖,也不能接触,即至少间隔一个方格。
  • 我们查询的位置一定使得它控制的区间不可使用,即这样会使得战舰的最多个数cnt减少。
  • 我们定义一个set,维护它的上下界。没把一次查询的位置pos插入set,查询set的上界r和下界l,上与下界的差值/(a+1) 这段区间可放战舰的个数,其中该位置需要使得长度为a的区间无效,那么剩余的区间可放,那么 (r - l)/(a+1) - (r-pos)/(a+1) - (l-pos)/(a+1) = 此次查询使得战舰减少的个数d。
  • 我们判断,如果cnt - d < k 那么此次查询必不合法。
  • 以上。

AC代码:

#include<bits/stdc++.h>
using namespace std;

#define IO          ios_base::sync_with_stdio(0),cin.tie(0)
#define pb(x)       push_back(x)
#define sz(x)       (int)(x).size()
#define abs(x)      ((x) < 0 ? -(x) : x)
#define mk(x,y)     make_pair(x,y)
#define fin         freopen("in.txt","r",stdin)
#define fout        freopen("out.txt","w",stdout)

typedef long long ll;
typedef pair<int,int> P;
const int mod = 1e9+7;
const int maxm = 1e8+5;
const int maxn = 2e5+5;
const int INF = 0x3f3f3f3f;
const ll LINF = 1ll<<62;

bool vis[maxn];
set<int> s;
int main()
{
//    fin;
    IO;
    int n,k,a,m;
    cin>>n>>k>>a;
    cin>>m;
    s.insert(0);
    s.insert(n+1);
    int res = (n+1)/(a+1);
    for(int i=1;i<=m;i++)
    {
        int e;
        cin>>e;
        if(vis[e]) continue;
        else vis[e] = true;
        s.insert(e);
        auto l = s.lower_bound(e);
        l--;
        auto r = s.upper_bound(e);
        int drs = (*r-*l)/(a+1) - (*r-e)/(a+1) - (e-*l)/(a+1);
        res -= drs;
        if(res < k){
            cout<<i<<endl;
            return 0;
        }
    }
    cout<<-1<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_37624640/article/details/84071317
今日推荐