Codeforces Round #543 (Div. 2, based on Technocup 2019 Final Round) D. Diana and Liana

题目链接

Description

一段长度为\(m\)的序列\(a\),按顺序分为\(n\)块,每块大小为\(k\)
可以删除一些数,要求删除后 \(m\geq n*k\)
再给定一个长度为\(s\)的序列\(b\),问是否能通过删除一些数(或不删),
使得至少一块中每个数出现的次数都不小于\(b\)中出现的次数。

Solution

哈又是一道用劣法过掉的题目。

首先只需要有一块满足条件即可。
假设以\(i\)为某一块的开头,那么需要删除\((i-1)\)%\(k\)个数(因为按顺序分块),
所有\(i\)最远能取到的数\(Next[i]\)就是\(i+k-1+n*k-m-((i-1)\)%\(k)\)
也就是说我们可以从\((i,Next[i])\)中任选\(k\)个数组成一块。

那么将\((i,Next[i])\)当作一个询问,莫队搞一搞就好啦。
时间复杂度\(O(m\sqrt{m})\)

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;

#define N 500000

#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define F(x) ((x + 1) / sq)

void read(int &x) {
    char ch = getchar(); x = 0;
    while (ch < '0' || ch > '9') ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + ch - 48, ch = getchar();
}

struct Ques { int l, r; } q[N + 1];

int a[N + 1], b[N + 1], d[N + 1], h[N + 1];

int n, m, k, s, cnt = 0, tot = 0, sq;

bool Cmp(Ques a, Ques b) { return F(a.l) < F(b.l) || (F(a.l) == F(b.l) && ((F(a.l) & 1) ? a.r < b.r : a.r > b.r)); }

void Add(int u) { if (++ h[a[u]] == d[a[u]]) -- cnt; }

void Del(int u) { if (h[a[u]] == d[a[u]]) ++ cnt; -- h[a[u]]; }

int main() {
     freopen("diana.in", "r", stdin);
     freopen("diana.out", "w", stdout);

    read(m), read(k), read(n), read(s);
    fo(i, 1, m) read(a[i]);
    fo(i, 1, s) read(b[i]);

    fo(i, 1, s) if (++ d[b[i]] == 1) ++ cnt;
    fo(i, 1, m - k + 1) if (m - n * k - (i - 1) % k >= 0)
        q[ ++ tot ] = (Ques) { i, i + k - 1 + m - n * k - (i - 1) % k };
    sq = sqrt(tot);
    sort(q + 1, q + 1 + tot, Cmp);

    for(int l = 1, r = 0, i = 1; i <= tot; i ++) {
        while (r < q[i].r) Add(++ r);
        while (l > q[i].l) Add(-- l);
        while (r > q[i].r) Del(r --);
        while (l < q[i].l) Del(l ++);
        if (! cnt) {
            printf("%d\n", m - n * k);
            fo(j, 1, (q[i].l - 1) % k) printf("%d ", j);
            int sum = 0;
            fo(j, q[i].l, q[i].r)
                if (h[a[j]] > d[a[j]] && ++ sum <= m - n * k - (q[i].l - 1) % k)
                    printf("%d ", j), -- h[a[j]];
            return 0;
        }
    }
    puts("-1");

    return 0;
}

posted @ 2020-10-07 16:38  buzzhou  阅读(88)  评论(0编辑  收藏  举报