BOI 2007 The Sound of Silence
Posted in 国外竞赛 on 五月 21st, 2010 by 纳米 – 3 Comments题目大意:
给定n个数,求出所有满足以下条件片段的起始位置:片段长度为M、片段内最大数和最小数的差小于给定的c。
解题报告:
这道题是《1D/1D动态规划优化初步》里面的例题,其实跟动态规划没啥关系,只是用到了一个单调队列优化。这个问题实质就是求每一个片段中最大值和最小值。因为求最小值和最大值本质是一样的,所以以最小值为例:
维护一个单调不下降的队列,每次遇到一个数,首先在队列头,若存在位置在这个数m个位置之前的元素,删掉。然后,在队列尾检查,若存在比该数大的元素,删掉。再在队列尾加入该数。这样,我们就得到了一个单调不下降序列。容易知道,队列头的元素就是以该数结尾的片段中最小的数字。
求出了每个片段中的最大值和最小值,问题就解决了。每个数只可能进、出一次队列,所以时间复杂度为O(n)。
我很恶心地使用了Class来实现这个代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | #include <stdio.h> const char IN_FILE_NAME[] = "sound.in"; const char OUT_FILE_NAME[] = "sound.out"; const int maxn = 1000005, maxm = 10005; int n, m, c, data[maxn]; class Queue { private: int num[maxn], pos[maxn], head, last; public: Queue() { head = 1; last = 0; } bool Empty() { return head > last; } int GetFirstNum() { return num[head]; } int GetFirstPos() { return pos[head]; } int GetLastNum() { return num[last]; } void DelFirst() { ++head; } void DelLast() { --last; } void Insert(int n, int p) { num[++last] = n; pos[last] = p; } } qmin, qmax; bool answer[maxn]; int input() { FILE *fin = fopen(IN_FILE_NAME, "r"); fscanf(fin, "%d%d%d", &n, &m, &c); for (int i = 1; i <= n; ++i) fscanf(fin, "%d", &data[i]); fclose(fin); return 0; } int work() { for (int i = 1; i < m; ++i) { while (!qmin.Empty() && qmin.GetLastNum() > data[i]) qmin.DelLast(); qmin.Insert(data[i], i); while (!qmax.Empty() && qmax.GetLastNum() < data[i]) qmax.DelLast(); qmax.Insert(data[i], i); } for (int i = m, j = 1; i <= n; ++i, ++j) { while (!qmin.Empty() && qmin.GetFirstPos() < j) qmin.DelFirst(); while (!qmin.Empty() && qmin.GetLastNum() > data[i]) qmin.DelLast(); qmin.Insert(data[i], i); while (!qmax.Empty() && qmax.GetFirstPos() < j) qmax.DelFirst(); while (!qmax.Empty() && qmax.GetLastNum() < data[i]) qmax.DelLast(); qmax.Insert(data[i], i); answer[j] = qmax.GetFirstNum() - qmin.GetFirstNum() <= c; } return 0; } int output() { FILE *fout = fopen(OUT_FILE_NAME, "w"); bool is_ok = false; for (int i = 1; i <= n; ++i) if (answer[i]) { fprintf(fout, "%d\n", i); is_ok = true; } if (!is_ok) fprintf(fout, "NONE\n"); fclose(fout); return 0; } int main() { input(); work(); output(); return 0; } |