题目:愚蠢的错误##

题意:中心公司有一个办公室有一个成熟的安全系统,这里面有106个雇员,编号从1到106
安全系统有入口和出口,数字i表示第i个雇员进入,-i表示第i个雇员出去

公司有一些严格的规矩:
1.雇员一天可以进入办公司最多一次
2.如果今天雇员没进雇员,他是无法出去的
3.办公室空的,代表里面的人都出去了

[1, 7, -7, 3, -1, -3]表示一个有效的一天,1进入,7进入,7出去,3进入,1出去,3出去

这里有a1,a2,...,an表示它们进出的序列,这个序列表示一天或者多天

你必须把这个序列划分成多天
例如:a = [1, -1, 1, 2, -1, 2, 3, -3]可以被划分成[1, -1| 1, 2, -1, -2, 3, -3],
即两天

如果没有有效的划分,输出-1
如果有有效的划分,输出划分的天数和每段的元素个数,如果有多个答案,输出一种就行(暗示贪心)

分析:解决这个问题有一种直观的贪心做法,模拟序列的进出,只要办公室出现一次空的,就记录划分的段数,
新开一天
为了有效地模拟这个问题,我们可以给予数组中每个雇员三种状态:进入办公室/在办公室里/离开办公室
每当我们结束一天,只需要重置参与的员工的状态
时间复杂度:O(n + e)

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <algorithm>
 
using namespace std;
const int N = 1000005;
int n;
vector<int> off;//办公室
vector<int> sec;//段
int state[N];//每个雇员的状态
const int WAIT = 0, ENTERED = 1, LEFT = 2;
int solve()
{
	scanf("%d", &n);
	int len = 0;
	int em;//雇员
	for (int i = 1; i <= n; ++i)
	{
		cin >> em;
		int guy = abs(em);
		off.push_back(guy);
		if (em > 0)//进入
		{
			if (state[guy] != WAIT)return false;
			state[guy] = ENTERED;
			++len;
		}
		else {//出去
			if (state[guy] != ENTERED)return false;
			state[guy] = LEFT;
			--len;
		}
		if (len == 0)
		{
			sec.push_back(off.size());
			for (int x : off)state[x] = WAIT;
			off.clear();
		}
	}
 
	if (!off.empty())return false;
 
	int nDays = sec.size();
 
	cout << nDays << endl;
 
	for (auto t : sec)
	{
		cout << t << " ";
	}
	return true;
}
 
int main()
{
	if (!solve())
		cout << "-1\n";
		
 
 
 
	return 0;
}