【集合】CFdiv.2#600B Silly Mistake

题目链接:https://codeforces.com/contest/1253/problem/B

  						B. Silly Mistake time 

limit per test1 second
memory limit per test256
megabytes inputstandard input outputstandard output The Central
Company has an office with a sophisticated security system. There are
106 employees, numbered from 1 to 106.
The security system logs entrances and departures. The entrance of the i-th employee is denoted by the integer i, while the
departure of the i-th employee is denoted by the integer −i.
The company has some strict rules about access to its office:
An employee can enter the office at most once per day. He obviously can’t leave the office if he didn’t enter it earlier that
day. In the beginning and at the end of every day, the office is
empty (employees can’t stay at night). It may also be empty at any
moment of the day. Any array of events satisfying these conditions
is called a valid day.
Some examples of valid or invalid days:
[1,7,−7,3,−1,−3] is a valid day (1 enters, 7 enters, 7 leaves, 3 enters, 1 leaves, 3 leaves). [2,−2,3,−3] is also a valid day.
[2,5,−5,5,−5,−2] is not a valid day, because 5 entered the office
twice during the same day. [−4,4] is not a valid day, because 4 left
the office without being in it. [4] is not a valid day, because 4
entered the office and didn’t leave it before the end of the day.
There are n events a1,a2,…,an, in the order they occurred. This array
corresponds to one or more consecutive days. The system administrator
erased the dates of events by mistake, but he didn’t change the order
of the events.
You must partition (to cut) the array a of events into contiguous subarrays, which must represent non-empty valid days (or
say that it’s impossible). Each array element should belong to
exactly one contiguous subarray of a partition. Each contiguous
subarray of a partition should be a valid day.
For example, if n=8 and a=[1,−1,1,2,−1,−2,3,−3] then he can partition it into two contiguous subarrays which are valid days:
a=[1,−1 | 1,2,−1,−2,3,−3].
Help the administrator to partition the given array a in the required way or report that it is impossible to do. Find any
required partition, you should not minimize or maximize the number
of parts.
Input The first line contains a single integer n (1≤n≤105).
The second line contains n integers a1,a2,…,an (−106≤ai≤106 and ai≠0).
Output If there is no valid partition, print −1. Otherwise, print any valid partition in the following format:
On the first line print the number d of days (1≤d≤n). On the second line, print d integers c1,c2,…,cd (1≤ci≤n and c1+c2+…+cd=n),
where ci is the number of events in the i-th day. If there are many
valid solutions, you can print any of them. You don’t have to
minimize nor maximize the number of days.

Examples
inputCopy
6 1 7 -7 3 -1 -3
outputCopy
1 6
inputCopy
8
1 -1 12 -1 -2 3 -3
outputCopy
2 2 6
inputCopy
6
2 5 -5 5 -5 -2
outputCopy
-1
inputCopy
3
-8 1 1
outputCopy
-1
Note
In the first example, the whole array is a valid day.

In the second example, one possible valid solution is to split the
array into [1,−1] and [1,2,−1,−2,3,−3] (d=2 and c=[2,6]). The only
other valid solution would be to split the array into [1,−1],
[1,2,−1,−2] and [3,−3] (d=3 and c=[2,4,2]). Both solutions are
accepted.

In the third and fourth examples, we can prove that there exists no
valid solution. Please note that the array given in input is not
guaranteed to represent a coherent set of events.

第一次用到unordered_set,纪念一下

一个set“s”判断该数是否进,一个set"v"判断该数是否进
由于unordered_set的性质,每次count(x)时间复杂度为O(1),可以很快地在集合中进行查找(用set也可以,快logn倍),刚开始是用vis[N]来判断是否进过,加了memset然后TLE,困得不行就去睡了(从不畏惧掉分),另外给出一种数组模拟集合的做法(感谢楠神支持)
unordered_set版:

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;

unordered_set<int> v, s;

int n, x;
vector<int> ans;
int main()
{
    cin >> n;
    int f = 0;
    int cnt = 0, cot = 0;
    for (int i = 1; i <= n; i++)
    {
        cin >> x;
        if (!s.size())
        {
            cnt++;
            v.clear();
            if (cot)
            {
                ans.push_back(cot);
                cot = 0;
            }
        }
        if (x > 0 && !v.count(x) && !s.count(x))
            v.insert(x), s.insert(x);
        else if (x < 0 && s.count(-x))
            s.erase(-x);
        else
            f = 1;
        cot++;
    }
    if (cot)
        ans.push_back(cot);

    if (s.size() || f)
    {
        puts("-1");
        return 0;
    }
    else
    {
        cout << cnt << endl;

        for (int i = 0; i < cnt; i++)
        {
            cout << ans[i] << " ";
        }
        cout << endl;
    }
	//system("pasue");  //记得注释掉,会RE
	return 0;
}

恪楠大佬的数组模拟集合

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

const int MAXN = 1e6 + 50;

int vis1[MAXN], vis2[MAXN];
// is1是否入队。vis2是否有过一次。 
vector<int> ans, jl;

int main()
{
    int n;
    int cnt = 0, size = 0, flag = 1;

    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
    {
        int t;
        scanf("%d", &t);

        if (t > 0)
        {
            if (vis2[t])
            {
                flag = 0;
            }

            jl.push_back(t);
            vis1[t] = 1;
            vis2[t] = 1;
            size++;
            cnt++;
        }
        else
        {
            t = -t;

            if (!vis1[t])
            { //cout << i << " " << vis1[t] << " ";
                flag = 0;
            }

            else
            {
                cnt--;
                size++;
                vis1[t] = 0;
                if (!cnt)
                {

                    ans.push_back(size);

                    for (int j = 0; j < jl.size(); j++)
                        vis2[jl[j]] = 0;

                    size = 0;
                }
            }
        }
    }
    if (cnt == 0 && size)
        ans.push_back(size);

    if (cnt)
        flag = 0;

    if (flag)
    {
        printf("%d\n", ans.size());
        for (int i = 0; i < ans.size(); i++)
        {
            printf("%d ", ans[i]);
        }
    }
    else
        printf("-1");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值