CF 1253B 模拟,贪心

CF1253B

题意:给一串数字有正有负,将这些数字分成任意段,满足每一段内部的数字都是成对出现的即出现一个整数就要有其相反数存在于其对应,并且每个数字只能出现一次,并且负数不能在正数的前面出现。

解题思路:从头开始遍历所有的数字,一旦出现满足题意的段,就存下来。例如样例给出的

8

1  -1  1  2  -1  -2  3  -3
这一组数,虽然可以分成两段,分别是前两个和后6个,但是也可以分成三段,长度分别为2,4,2。这样做的好处就是可以让每一段的满足条件相同,即满足了贪心的条件,如果采用样例给出的答案来看的话,使两段满足的条件并不完全相等,就不好处理。

容易出错的点:

首先就是特别容易T,因为每存一段就是一次更新,如何更新用过的点的状态,一开始我采用了memset直接把整个用来标记状态的数组更新,但是很明显T了,因为在更新的时候有很多点都是没有用上的,这样来更新大数组的话很容易超时,后来就用了队列来保存某一段中出现过的点,那么在每一次更新的时候,只要边清空队列,边把队列中的元素更新就可以了,节约了很多时间。

其次就是用bool数组的话容易出错,因为可能存在的情况不止2种,比如 1  2  -2  -2这组数据的话,当处理到第一个-2的话,并不满足题意,但是当处理到第二个-2的话,由于没有记录-2出现的此处,很容易就在这里满足题意。造成错误,这里可能会有点看不懂,结合代码的注释就可以看懂了

 1 #include <iostream>
 2 #include <cstring>
 3 #include <string>
 4 #include <algorithm>
 5 #include <queue>
 6 #include <stack>
 7 #include <stdio.h>
 8 #include <cmath>
 9 #include <string.h>
10 #include <vector>
11 using namespace std;
12 #define ll long long
13 static const int WHITE=0;
14 static const int GRAY=1;
15 static const int BLACK=2;
16 static const int INF=0x3f3f3f3f;
17 int v[1000005];
18 vector <int> vec;//用来记录分成了多少段以及每一段的长度
19 queue <int> q;
20 int main()
21 {
22     int n;
23     int a[100005];
24     cin>>n;
25     for(int i=1;i<=n;i++)
26     cin>>a[i];
27     int i=0,k=0;
28     vec.push_back(0);
29     while(i<=n)
30     {
31         i++;
32         while(!q.empty())//每一段开始就要把上一段用过的点更新
33         {
34             v[q.front()]=0;
35             q.pop();
36         }
37         k=0;
38         bool flag=true;
39         for(;i<=n;i++)
40         {
41             if(a[i]<0)//当出现负数的时候
42             {
43                 if(v[-a[i]]!=1)//如果对应的正数没有出现过,或者其本身出现过不止一次,则错误
44                 {
45                     flag=false;
46                     break;
47                 }
48                 else//如果对应的正数出现过
49                 {
50                     k--;//每出现一次正数k++,那么当k==0的时候满足所有数成对出现
51                     v[-a[i]]++;//当某一对数已经出现的话,其绝对值对应的v的值应为1,所以如果大于1的话就说明第二次出现,不满足
52                     if(k==0)
53                     {
54                         vec.push_back(i);
55                         break;
56                     }
57                 }
58             }
59             else
60             {
61                 if(v[a[i]]!=0)//正数不是第一次出现,不满足每一对数只出现一次
62                 {
63                     flag=false;
64                     break;
65                 }
66                 else//第一次出现,记录
67                 {
68                     v[a[i]]=1;
69                     q.push(a[i]);
70                     k++;
71                 }
72             }
73         }
74         if(!flag)
75         {
76             cout<<"-1"<<endl;
77             return 0;
78         }
79     }
80     if(k!=0||vec.size()==1)
81     cout<<"-1"<<endl;
82     else
83     {
84         cout<<vec.size()-1<<endl;
85         for(int i=1;i<vec.size();i++)
86         {
87             cout<<vec[i]-vec[i-1]<<" ";
88         }
89     }
90     cout<<endl;
91     return 0;
92 }
原文地址:https://www.cnblogs.com/zlhdbk/p/11971675.html