2020牛客NOIP赛前集训营-提高组(第六场)B 艰难睡眠

艰难睡眠

https://ac.nowcoder.com/acm/contest/7615/B

什么泄出题人比赛开始了两个小时才改好题面。

首先枚举连续睡觉时间的开始,则可以算出在这一段时间内吵闹的人转移到的可行区间。

这样问题就变成每次有一段可行区间求区间最小值。

直接st表肯定是不行的,但是注意到每次睡觉时间只会往后移动1,那么吵闹的人转移到的可行区间的l和r也只会变化1。

这样我们可以用单调队列维护,具体的在时间1把可行区间里的所有吵闹的人加入单调队列,然后右移左右端点,加入右端点的权值,更新即可。

注意到每个人对答案的贡献是独立的,所以可以每个人分开算,即每个人算出睡眠左端点为i时的最小值,最后把所有人的答案相加即可。

然后这题是个环,为了方便处理可以断环成链。

/*
    _______                       ________                        _______
   / _____ \                     / ______ \                      / _____ \
  / /     \_\  _     __     _   / /      \ \   _     __     _   / /     \_\
 | |          | |   |  |   | | | |        | | | |   |  |   | | | |
 | |          | |   |  |   | | | |     __ | | | |   |  |   | | | |
 | |       __ \  \  |  |  /  / | |     \ \| | \  \  |  |  /  / | |       __
  \ \_____/ /  \  \/ /\ \/  /   \ \_____\  /   \  \/ /\ \/  /   \ \_____/ /
   \_______/    \___/  \___/     \______/\__\   \___/  \___/     \_______/
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>

using namespace std;

#define ll long long

const int N = 5000;
const ll INF = 1e18;

int n, m, k, c[N + 50];

ll ans[2050];

struct Node
{
    int a, b;
} a[N + 50];

void Read(int &x)
{
    x = 0; int p = 0; char st = getchar();
    while (st < '0' || st > '9') p = (st == '-'), st = getchar();
    while (st >= '0' && st <= '9') x = (x << 1) + (x << 3) + st - '0', st = getchar();
    x = p ? -x : x;
    return;
}

struct Nod
{
    int id, qz;
};

deque<Nod> q; 

namespace io {
const int L = (1 << 21) + 1;
char ibuf[L], *iS, *iT, obuf[L], *oS = obuf, *oT = obuf + L - 1, c, st[55];
int f, tp;
#define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,L,stdin),(iS==iT?EOF:*iS++)):*iS++)
inline void gi(int& x) { //get
    for (f = 1, c = gc(); c < '0' || c > '9'; c = gc())
        if (c == '-') f = -1;
    for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15);
    x *= f;
}
};  // namespace io
using io::gi;

int main()
{
    gi(n); gi(m); gi(k);
    for (int i = 1; i <= n; i++) 
    {
        gi(a[i].a), gi(a[i].b);
        if (a[i].b > m - k) 
        {
            puts("-1");
            return 0;
        }
    }
    int l, r;
    for (int i = 1; i <= n; i++)
    {
        while (!q.empty()) q.pop_front();
        for (int j = 1; j <= m; j++)
            gi(c[j]), c[j + m] = c[j];
        l = k + 1;
        r = m - a[i].b + 1;
        for (int j = l; j <= r; j++)
        {
            while (!q.empty() && q.back().qz >= c[j]) q.pop_back();
            q.push_back((Nod){j, c[j]});
        }
        ans[1] += q.front().qz;
        for (int j = 2; j <= m; j++)
        {
            l++; r++;
            while (!q.empty() && q.front().id < l) q.pop_front();
            while (!q.empty() && q.back().qz >= c[r]) q.pop_back();
            q.push_back((Nod){r, c[r]});
            ans[j] += q.front().qz;
        }
    }
    ll answer = ans[1];
    for (int i = 2; i <= m; i++) answer = min(answer, ans[i]);
    printf("%lld", answer);
    return 0;
}
全部评论

相关推荐

4 收藏 评论
分享
牛客网
牛客企业服务