#11.11 个人排位赛round2_A.Diana and Liana(CodeForces 1121D)

A.Diana and Liana

题目链接在此!

这题也是心理变态出的。头疼!

A.Diana and Liana(CodeForces 1121D)
At the first holiday in spring, the town Shortriver traditionally conducts a flower festival. Townsfolk wear traditional wreaths during
these festivals. Each wreath contains exactly k flowers.

The work material for the wreaths for all n citizens of Shortriver is
cut from the longest flowered liana that grew in the town that year.
Liana is a sequence a1, a2, …, am, where ai is an integer that
denotes the type of flower at the position i. This year the liana is
very long (m≥n⋅k), and that means every citizen will get a wreath.

Very soon the liana will be inserted into a special cutting machine in
order to make work material for wreaths. The machine works in a simple
manner: it cuts k flowers from the beginning of the liana, then
another k flowers and so on. Each such piece of k flowers is called a
workpiece. The machine works until there are less than k flowers on
the liana.

Diana has found a weaving schematic for the most beautiful wreath
imaginable. In order to weave it, k flowers must contain flowers of
types b1, b2, …, bs, while other can be of any type. If a type
appears in this sequence several times, there should be at least that
many flowers of that type as the number of occurrences of this flower
in the sequence. The order of the flowers in a workpiece does not
matter.

Diana has a chance to remove some flowers from the liana before it is
inserted into the cutting machine. She can remove flowers from any
part of the liana without breaking liana into pieces. If Diana removes
too many flowers, it may happen so that some of the citizens do not
get a wreath. Could some flowers be removed from the liana so that at
least one workpiece would conform to the schematic and machine would
still be able to create at least n workpieces?

Input The first line contains four integers m, k, n and s
(1≤n,k,m≤5⋅105, k⋅n≤m, 1≤s≤k): the number of flowers on the liana, the
number of flowers in one wreath, the amount of citizens and the length
of Diana’s flower sequence respectively.

The second line contains m integers a1, a2, …, am (1≤ai≤5⋅105) —
types of flowers on the liana.

The third line contains s integers b1, b2, …, bs (1≤bi≤5⋅105) — the
sequence in Diana’s schematic.

Output If it’s impossible to remove some of the flowers so that there
would be at least n workpieces and at least one of them fullfills
Diana’s schematic requirements, output −1.

Otherwise in the first line output one integer d — the number of
flowers to be removed by Diana.

In the next line output d different integers — the positions of the
flowers to be removed.

If there are multiple answers, print any.

Examples Input 7 3 2 2 1 2 3 3 2 1 2 2 2 Output 1 4 Input 13 4 3 3 3
2 6 4 1 4 4 7 1 3 3 2 4 4 3 4 Output
-1 Input 13 4 1 3 3 2 6 4 1 4 4 7 1 3 3 2 4 4 3 4 Output 9 1 2 3 4 5 9 11 12 13 Note In the first example, if you don’t remove any flowers,
the machine would put out two workpieces with flower types [1,2,3] and
[3,2,1]. Those workpieces don’t fit Diana’s schematic. But if you
remove flower on 4-th place, the machine would output workpieces
[1,2,3] and [2,1,2]. The second workpiece fits Diana’s schematic.

In the second example there is no way to remove flowers so that every
citizen gets a wreath and Diana gets a workpiece that fits here
schematic.

In the third example Diana is the only citizen of the town and that
means she can, for example, just remove all flowers except the ones
she needs.

题目大意:

n 朵花,每连续的 k 朵 可以组成一个花环。
组成共 m 个花环,其中一个花环中的 s 朵花必须满足给定的序列(接着给出s朵花的种类)。
也就是说,其中一个连续 k 朵花组成的花环中必须包含那 s 种花。
求出最大可以删除的花朵,并输出这些花的坐标。
答案不唯一,输出任意一个。

题意分析:

明显是尺取算法。
想起前段时间有人和我说尺取的时候打成吃蛆,这也太恐怖了。
我的想法是:
等同于
len = n - k * m + k;
尺取区间的最大长度是:
最多删除的花朵数量(总量-花环)+一只花环需要的数量。
ans=这个区间删除 n-m*k 朵多余的花
del = n - k * m;
从开头维护一个长度为 len 的区间[l,r]看符不符合题意,不符合就往后一个一个挪动,更新左右端点以及挪动造成的影响。

还有一点,虽然其它花环没有特殊要求,但也必须是连续的 k 个才能组成花环。所以,这个区间外左右两边必须都是 k 的倍数。

感觉思路写的还是很清楚的。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <string>
#include <cstring>
#include <list>
#include <queue>
#include <stack>
#include <set>
#include <algorithm>
#include <cmath>
#include <map>
#include <unordered_map>
#include <iomanip>

#define INF 0x3f3f3f3f
#define pi acos(-1)
#define M 110
using namespace std;
typedef long long ll;

using namespace std;
const int maxn = 5e5 + 10;

int a[maxn];
int need[maxn] = {0};
int cnt[maxn] = {0};
int ans[maxn] = {0};
bool vis[maxn] = {0};
//经典大数组放外面

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n, k, m, s;
    cin >> n >> k >> m >> s;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    int len = n - k * m + k;
    //尺取区间
    int del = n - k * m;
    //这些在思路里都写的很清楚了
    int kinds = 0;

    for (int i = 1; i <= s; i++) {
        int temp;
        cin >> temp;

        if (!need[temp])
        //如果还没标记过
         {
            vis[temp] = 1;
            //标记一下此种花需要
            kinds++;
            //需要的花种类变多

        }
        ++need[temp];
    }

    bool flag = 0;
    //判断循环结束
    int L = 1;
    for (int i = 1; i <= len; i++)
    //第一个区间
     {
        int temp = a[i];
        cnt[temp]++;
        if (vis[temp] && cnt[temp] == need[temp])
            kinds--;
        if (kinds == 0) {
            L = 1;
            flag = 1;
            break;
            //刚好第一个区间就满足
        }
    }
    if (!flag)
        for (int i = len + 1; i <= n; i++) {
            int l = a[L];
            //储存上一个区间最左
            int r = a[i];
             //储存上一个区间最左
            L++;

            cnt[l]--;
            //最左边的花没了。
            if (vis[l])
             //最左边的花是需要的
             {
                if (cnt[l] == need[l] - 1)
                //刚刚好去掉左边那朵就不够了的时候才会导致数量++
                //不然便是之前就不够or少了一朵也没关系
                    kinds++;
            }
            cnt[r]++;
            //最右边的花多了
            if (vis[r])
            //最右边的花是需要的
            {
                if (cnt[r] == need[r])
                    kinds--;
            }
            if (kinds == 0 && (L - 1) % k == 0) 
//思路里分析过的,只要判断左端点即可,因为区间大小特别。
			{
                flag = 1;
                break;
            }
        }

    int num = 0;
    if (flag) 
//有解
	{
        for (int i = L; i < len + L; i++) 
        {//此为解所在区间
            int temp = a[i];
            if (need[temp] > 0) {
                need[temp]--;
                continue;
                //不能被删掉
            }
            if (num == del) break;
            //被删掉的数量应该刚好等于del
            ans[++num] = i;
        }
        cout << num << endl;

        for (int i = 1; i <= num; i++) {
            if(i!=num) cout << ans[i] << ' ';
            else cout << ans[num] << endl;
        }
    } else cout << -1 << endl;
    return 0;
}

感觉写的好清楚了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值