卡牌游戏

题目传送门

题目大意

Alice n n n 张卡牌,第 i ( 1 ≤ i ≤ n ) i(1≤i≤n) i1in张卡牌的正面有数字 a i a_i ai,背面有数字 b i b_i bi,初始时所有卡牌正面朝上。

现在 Alice 可以将不超过 m m m 张卡牌翻面,即由正面朝上改为背面朝上。

Alice 的目标是让最终朝上的 n n n 个数字的极差(最大值与最小值的差)尽量小。

请你帮 Alice 算一算极差的最小值是多少。

解题思路

似乎是省选 D 1 T 1 D1T1 D1T1,不过好像也没那么难。

对于数字考虑,极差最小就是对于排序之后的数组中,取一个长度最短的区间。

我们把 a i a_i ai b i b_i bi 都放进去排序,取 n n n 张牌至少出现一次且反面向上的不超过 m m m 张的区间,用双指针维护即可(我们可以通过双指针删除前面一段和后面一段,这样直接判断中间那一段就好了)。

时间复杂度 O ( n ) \mathcal{O}(n) O(n)

AC CODE

#include <bits/stdc++.h>
#include <array>
using namespace std;
const int maxn = 2e6 + 5;

inline int read()
{
    char c = getchar();
    int x = 0;
    bool f = 0;
    for (; !isdigit(c); c = getchar())
    {
        f ^= !(c ^ 45);
    }
    for (; isdigit(c); c = getchar())
    {
        x = (x << 1) + (x << 3) + (c ^ 48);
    }
    if (f)
    {
        x = -x;
    }
    return x;
}

inline void write(int x)
{
    if (x < 0)
    {
        putchar('-');
        x = -x;
    }
    if (x > 9)
    {
        write(x / 10);
    }
    putchar(x % 10 + '0');
}

struct abc
{
    int val;
    int id;
    int flag;
};
int n, m, x, ans = INT_MAX;
int l, r, now;
array<bool, maxn> vis;
array<abc, maxn> e;

bool cmp(abc x, abc y)
{
    return x.val < y.val;
}

bool check(int x)
{
    return (!vis[e[x].id] && (now + e[x].flag <= m));
}

void add(int x)
{
    now += e[x].flag;
    vis[e[x].id] = true;
}

void del(int x)
{
    now -= e[x].flag;
    vis[e[x].id] = false;
}

signed main()
{
    n = read();
    m = read();
    for (int i = 1; i <= n; i++)
    {
        x = read();
        e[i].val = x;
        e[i].id = i;
        e[i].flag = 1;
    }
    for (int i = 1; i <= n; i++)
    {
        x = read();
        e[i + n].val = x;
        e[i + n].id = i;
        e[i + n].flag = 0;
    }
    sort(e.begin() + 1, e.begin() + n * 2 + 1, cmp);
    l = 0;
    r = n * 2 + 1;
    now = 0;
    while (check(l + 1))
        add(++l);
    while (check(r - 1))
        add(--r);
    while (l)
    {
        ans = min(ans, e[r - 1].val - e[l + 1].val);
        del(l--);
        while (check(r - 1))
            add(--r);
    }
    write(ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值