只是贴代码,这种模拟题一定要好好纪念下 TAT
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAXN = (int) 1e5+10; bool is[MAXN]; int msg[MAXN]; int first_in[MAXN], last_in[MAXN], last_out[MAXN]; bool flag[MAXN]; bool in[MAXN]; char str[10]; int n, m; int st; void print() { printf("st: %d, m:%d ", st, m); for (int i = 1; i <= n; i++) printf("%d ", first_in[i]); puts(""); for (int i = 1; i <= n; i++) printf("%d ", last_in[i]); puts(""); for (int i = 1; i <= n; i++) printf("%d ", last_out[i]); puts(""); for (int i = 1; i <= n; i++) printf("%d ", flag[i]); puts(""); } /** 我们可以分为如下几种情况: 1. 从来没出现过 2. 进入时,或者出去时有其他人 3. 进入时没人,但进来前其他人来过 4. */ int main() { #ifdef Phantom01 freopen("C.txt", "r", stdin); #endif // Phantom01 while (scanf("%d%d", &n, &m)!=EOF) { st = 1; //第一个人的进入时间 int cnt = 0; memset(first_in, -1, sizeof(first_in)); memset(last_in, -1, sizeof(last_in)); memset(last_out, -1, sizeof(last_out)); //如果从没出去过,为-1 memset(flag, false, sizeof(flag)); memset(in, 0, sizeof(in)); int num = 0; for (int i = 1; i <= m; i++) { //记录时间从1开始 int t; scanf("%s%d", str, &t); //没有考虑到最后一刻还有人的情况 if ('+'==str[0]) { is[i] = true; if (-1==first_in[t]) first_in[t] = i; } else { is[i] = false; if (-1==first_in[t]) { first_in[t] = 0; num++; st = 0; } } msg[i] = t; } //print(); for (int i = 1; i <= m; i++) { int t = msg[i]; if (is[i]) { last_in[t] = i; //记录最近进入时间(好像没必要) if (last_out[t]>0 && last_in[t]-last_out[t]>1) { //如果上次出去的时间不是在前一个时刻,那么中间一定有人进来 if (!flag[t]) { //若果没被标记过,就标记他不符合情况 flag[t] = true; cnt++; } } num++; } else { last_out[t] = i; num--; if (num>0) { if (!flag[t]) { flag[t] = true; cnt++; } } } } for (int i = 1; i <= n; i++) { if (first_in[i]>st //如果首次进入时间在第一个进入之后, || ((last_out[i]>last_in[i]) //或者最后一次出去在 && ((num > 0) //里面还有人 || (0<last_out[i]&&last_out[i]<m )))) { //而且最后一次出去在最后一个人之前,一定不行 if (!flag[i]) { flag[i] = true; cnt++; } } } printf("%d ", n-cnt); bool flag2 = false; for (int i = 1; i <= n; i++) if (!flag[i]) { if (flag2) printf(" "); printf("%d", i); flag2 = true; } if (flag2) puts(""); } return 0; }