题解
总之就是非常奇怪
1 条题解
-
0
P4695 总之就是非常奇怪(【基础】)
解题思路
先看数组 k,里面出现过的数,乌鸡姐姐听不见,直接忽略。剩下没在 k 里的数字,每个数字第一次出现的时候她也听不见(耳背),之后再次出现才能听到。下面分四步实现。
**第一步,快速读入。**数据量可能很大(可达千万级),所以用 fread 缓冲实现快速读入 readInt,用 putchar 缓存快速输出 writeInt,防止超时。
**第二步,标记 k 里的数。**数字的值域只有 -9 到 9,加 9 就能当数组下标,所以用 isInK 数组标记:
isInK[value + 9] = 1表示 value 在 k 里出现过。**第三步,遍历听牌。**对 m 个数逐个处理:如果在 isInK 里就直接忽略;如果没在 k 里但这是第一次出现(seenOnce 数组对应位置还是 0),把 seenOnce 标记为 1 然后忽略;否则说明这次能听到,把数存进 heardNums。
**第四步,输出。**每个测试样例输出一行,数之间用空格隔开;如果某个样例一个数都没听到(heardCnt 为 0),就什么都不输出,连换行也不输出。最后别忘了把输出缓冲区里的内容用 fwrite 清空。
边界情况:数字范围只有 -9 到 9,加 9 当下标,数组开 25 个足够;注意第一次出现的数要"听过一次"但不算听到,第二次才计入。
参考代码
// P4695 总之就是非常奇怪:忽略数组k中出现过的数,剩下的数里第一次出现的也忽略,输出听到的数组 // 数据量可达千万级,用 fread 缓冲实现快速读入,用 putchar 缓存快速输出 #include <cstdio> using namespace std; const int BS = 1 << 20; char ibuf[BS]; int ipos = 0, ilen = 0; // 从缓冲区读一个字符 inline char gc() { if (ipos >= ilen) { ilen = fread(ibuf, 1, BS, stdin); ipos = 0; if (ilen == 0) return -1; } return ibuf[ipos++]; } // 快速读入一个整数(支持负数) inline int readInt() { int num = 0, sign = 1; char c = gc(); while (c < '0' || c > '9') { if (c == '-') sign = -1; c = gc(); } while (c >= '0' && c <= '9') { num = num * 10 + c - '0'; c = gc(); } return num * sign; } const int OS = 1 << 20; char obuf[OS]; int opos = 0; // 把字符写入输出缓冲区 inline void pc(char c) { if (opos >= OS) { fwrite(obuf, 1, OS, stdout); opos = 0; } obuf[opos++] = c; } // 输出一个整数(不带空格) inline void writeInt(int value) { if (value < 0) { pc('-'); value = -value; } if (value == 0) { pc('0'); return; } char digits[12]; int digitLen = 0; while (value) { digits[digitLen++] = '0' + value % 10; value /= 10; } while (digitLen) pc(digits[--digitLen]); } int heardNums[1000005]; // 存最终听到的数(全局数组) int main() { int T = readInt(); while (T--) { int n = readInt(), m = readInt(); int isInK[25] = {0}; // 值域 -9~9,加9做下标,标记在k中出现过的数 for (int i = 0; i < n; i++) { int value = readInt(); isInK[value + 9] = 1; } int heardCnt = 0; int seenOnce[25] = {0}; // 该数第一次出现是否已被忽略 for (int i = 0; i < m; i++) { int value = readInt(); if (isInK[value + 9]) continue; // 在k中出现过,直接忽略 if (!seenOnce[value + 9]) { // 第一次出现,耳背听不见 seenOnce[value + 9] = 1; continue; } heardNums[heardCnt++] = value; // 之后的出现能听到 } if (heardCnt) { for (int i = 0; i < heardCnt; i++) { if (i) pc(' '); writeInt(heardNums[i]); } pc('\n'); } // heardCnt==0 时不输出任何内容(连换行也没有) } if (opos) fwrite(obuf, 1, opos, stdout); return 0; }复杂度分析
每个数字只被处理一次,单组数据的时间复杂度是 O(n+m),其中 m 最大 100 万。空间上用一个长度 m 的数组存输出,是 O(m)。
- 1