110MS, O(nlog(n))的算法,怎样才能更快?那些10几个MS的是怎样实现的?
1 Source Code
2 Problem: 1631 User: goldenlock
3 Memory: 628K Time: 110MS
4 Language: G++ Result: Accepted
5
6 * Source Code
7
8 /**
9 * ==============================================================================
10 *
11 * \file bridging_signals_1631.cc
12 *
13 * \author pku_goldenlock@qq.com
14 *
15 * \date 2009-10-28 21:41:57.539397
16 *
17 * Description: pku 1631,
18 * 本质上就是求最长只增序列,编程之美上
19 * 有解释.下面只要提到序列就是递增序列.
20 * 疑问,两个左边的指向同一个右边的算相交了吗?假定不算相交
21 * 不算的话就允许递增序列有相同大小的元素,如果算就不能有.
22 * 不管算不算相交,都是求upper_bound,如果不算的化,元素全
23 * 不相同.恩,本题目是没有相同元素的,不会左边两个连右边
24 * 同一个的.但是解法并不改变.
25 * 思路:
26 * 依次求以第n个元素结尾的只增序列长度l[n],记录所有的l[]最大的一个即
27 * 为所求.
28 * 核心优化:
29 * 最本质的规律是前面的l[k],l[j]相等的化, 假如data[k] < data[j]
30 * 那么后面元素就不需要去考虑data[j]!在同等长度下,尾元素小的序
31 * 列优先.
32 *
33 * 因此可以记录各个长度的序列,记录其对应的最小尾元素.
34 * 考虑长度为i(1,2,3,4.)这样的递增长度序列,其对应的最小尾元素t[i]也
35 * 是递增的.否则假如如果i > j 而t[i] < t[j] 则存在 x < t[i] < t[j]
36 * l[x] = t[j] 与t[j] 是长度为j的序列的最小尾元素矛盾.
37 *
38 * 因为递增长度对应的最小尾元素也递增,所以可以二分查找.
39 * 对于扫描到第n个元素, data[n],去最小尾元素序列二分查找
40 * data[n](stl upper_bound),返回第一个比data[n]大的位置k,令t[k] = data[n],
41 * 即更新长度位k的序列的最小尾元素值.
42 * 最后返回最长的那个序列的长度即可.
43 *
44 * ==============================================================================
45 */
46 #include <stdio.h>
47 /*
48 * for spped, your response to let end >= 0
49 * 对这个特殊的问题,没有相同元素,所以一定查找不到key
50 * 如1 2 4 查找3 返回index 2 t[2] = 4(upper_bound!)
51 * upper_bound和lower_bound的区别在于 upper_bound return start, lower_bound return end.
52 * search 1.5
53 * 1
54 * end start
55 * search 0.5
56 * 1
57 * end start
58 * 最后总是start指向比key大的第一个数字位置,end指向比key小的第一个位置
59 * the last status : end key start
60 * TODO try std::upper_bound, the same:)
61 */
62 inline int upper_bound(int t[], int end, int key) {
63 int start = 0;
64 int mid;
65 while (start <= end) {
66 mid = (start + end)/2;
67 //考虑假设有相同元素的情况(本题目没有),必须这么写,不能key <= t[mid],i
68 //lower_bound 要写 if key > t[mid] start = mid + 1
69 if (key < t[mid])
70 end = mid - 1;
71 else
72 start = mid + 1;
73 }
74 return start;
75 }
76
77 inline int maxIncreasingSequence(int data[], int len)
78 {
79 //--------------------init
80 int max_len = 0;
81 int t[len];
82 t[0] = data[0];
83 int pos;
84 //--------------------find max length
85 for (int i = 1; i < len; i++) {
86 pos = upper_bound(t, max_len, data[i]);
87 if (pos > max_len) //get longer sequence
88 max_len = pos;
89 //modify(or add) the smallest ending value
90 //for sequence with length as pos + 1
91 t[pos] = data[i];
92 }
93 //--------------------return
94 return max_len + 1; //due to staring index is 1 not 0
95 }
96
97 int main(int argc, char *argv[])
98 {
99 int test_num;
100 scanf("%d", &test_num);
101 int array_length;
102 //-----------------run each test case
103 for (int i = 0; i < test_num; i++) {
104 //------------------------get input
105 scanf("%d", &array_length);
106 int data[array_length];
107 for (int j = 0; j < array_length; j++) {
108 scanf("%d", &data[j]);
109 }
110 //------------------------print result
111 printf("%d\n", maxIncreasingSequence(data, array_length));
112 }
113 return 0;
114 }
115
116
2 Problem: 1631 User: goldenlock
3 Memory: 628K Time: 110MS
4 Language: G++ Result: Accepted
5
6 * Source Code
7
8 /**
9 * ==============================================================================
10 *
11 * \file bridging_signals_1631.cc
12 *
13 * \author pku_goldenlock@qq.com
14 *
15 * \date 2009-10-28 21:41:57.539397
16 *
17 * Description: pku 1631,
18 * 本质上就是求最长只增序列,编程之美上
19 * 有解释.下面只要提到序列就是递增序列.
20 * 疑问,两个左边的指向同一个右边的算相交了吗?假定不算相交
21 * 不算的话就允许递增序列有相同大小的元素,如果算就不能有.
22 * 不管算不算相交,都是求upper_bound,如果不算的化,元素全
23 * 不相同.恩,本题目是没有相同元素的,不会左边两个连右边
24 * 同一个的.但是解法并不改变.
25 * 思路:
26 * 依次求以第n个元素结尾的只增序列长度l[n],记录所有的l[]最大的一个即
27 * 为所求.
28 * 核心优化:
29 * 最本质的规律是前面的l[k],l[j]相等的化, 假如data[k] < data[j]
30 * 那么后面元素就不需要去考虑data[j]!在同等长度下,尾元素小的序
31 * 列优先.
32 *
33 * 因此可以记录各个长度的序列,记录其对应的最小尾元素.
34 * 考虑长度为i(1,2,3,4.)这样的递增长度序列,其对应的最小尾元素t[i]也
35 * 是递增的.否则假如如果i > j 而t[i] < t[j] 则存在 x < t[i] < t[j]
36 * l[x] = t[j] 与t[j] 是长度为j的序列的最小尾元素矛盾.
37 *
38 * 因为递增长度对应的最小尾元素也递增,所以可以二分查找.
39 * 对于扫描到第n个元素, data[n],去最小尾元素序列二分查找
40 * data[n](stl upper_bound),返回第一个比data[n]大的位置k,令t[k] = data[n],
41 * 即更新长度位k的序列的最小尾元素值.
42 * 最后返回最长的那个序列的长度即可.
43 *
44 * ==============================================================================
45 */
46 #include <stdio.h>
47 /*
48 * for spped, your response to let end >= 0
49 * 对这个特殊的问题,没有相同元素,所以一定查找不到key
50 * 如1 2 4 查找3 返回index 2 t[2] = 4(upper_bound!)
51 * upper_bound和lower_bound的区别在于 upper_bound return start, lower_bound return end.
52 * search 1.5
53 * 1
54 * end start
55 * search 0.5
56 * 1
57 * end start
58 * 最后总是start指向比key大的第一个数字位置,end指向比key小的第一个位置
59 * the last status : end key start
60 * TODO try std::upper_bound, the same:)
61 */
62 inline int upper_bound(int t[], int end, int key) {
63 int start = 0;
64 int mid;
65 while (start <= end) {
66 mid = (start + end)/2;
67 //考虑假设有相同元素的情况(本题目没有),必须这么写,不能key <= t[mid],i
68 //lower_bound 要写 if key > t[mid] start = mid + 1
69 if (key < t[mid])
70 end = mid - 1;
71 else
72 start = mid + 1;
73 }
74 return start;
75 }
76
77 inline int maxIncreasingSequence(int data[], int len)
78 {
79 //--------------------init
80 int max_len = 0;
81 int t[len];
82 t[0] = data[0];
83 int pos;
84 //--------------------find max length
85 for (int i = 1; i < len; i++) {
86 pos = upper_bound(t, max_len, data[i]);
87 if (pos > max_len) //get longer sequence
88 max_len = pos;
89 //modify(or add) the smallest ending value
90 //for sequence with length as pos + 1
91 t[pos] = data[i];
92 }
93 //--------------------return
94 return max_len + 1; //due to staring index is 1 not 0
95 }
96
97 int main(int argc, char *argv[])
98 {
99 int test_num;
100 scanf("%d", &test_num);
101 int array_length;
102 //-----------------run each test case
103 for (int i = 0; i < test_num; i++) {
104 //------------------------get input
105 scanf("%d", &array_length);
106 int data[array_length];
107 for (int j = 0; j < array_length; j++) {
108 scanf("%d", &data[j]);
109 }
110 //------------------------print result
111 printf("%d\n", maxIncreasingSequence(data, array_length));
112 }
113 return 0;
114 }
115
116
可以复用data数组,即不需要t数组,不过不改善什么性能.
1 #include <stdio.h>
2
3 inline int upper_bound(int data[], int end, int key) {
4 int start = 0;
5 int mid;
6 while (start <= end) {
7 mid = (start + end)/2;
8 //考虑假设有相同元素的情况(本题目没有),必须这么写,不能key <= t[mid],i
9 //lower_bound 要写 if key > t[mid] start = mid + 1
10 if (key < data[mid])
11 end = mid - 1;
12 else
13 start = mid + 1;
14 }
15 return start;
16 }
17
18 inline int maxIncreasingSequence(int data[], int len)
19 {
20 //--------------------init
21 int max_len = 0;
22 int pos;
23 //--------------------find max length
24 for (int i = 1; i < len; i++) {
25 pos = upper_bound(data, max_len, data[i]);
26 if (pos > max_len) //get longer sequence
27 max_len = pos;
28 data[pos] = data[i]; //modify smallest tail value
29 }
30 //--------------------return
31 return max_len + 1; //due to staring index is 1 not 0
32 }
33
34 int main(int argc, char *argv[])
35 {
36 int test_num;
37 scanf("%d", &test_num);
38 int array_length;
39 //-----------------run each test case
40 for (int i = 0; i < test_num; i++) {
41 //------------------------get input
42 scanf("%d", &array_length);
43 int data[array_length];
44 for (int j = 0; j < array_length; j++) {
45 scanf("%d", &data[j]);
46 }
47 //------------------------print result
48 printf("%d\n", maxIncreasingSequence(data, array_length));
49 }
50 return 0;
51 }
52
53
2
3 inline int upper_bound(int data[], int end, int key) {
4 int start = 0;
5 int mid;
6 while (start <= end) {
7 mid = (start + end)/2;
8 //考虑假设有相同元素的情况(本题目没有),必须这么写,不能key <= t[mid],i
9 //lower_bound 要写 if key > t[mid] start = mid + 1
10 if (key < data[mid])
11 end = mid - 1;
12 else
13 start = mid + 1;
14 }
15 return start;
16 }
17
18 inline int maxIncreasingSequence(int data[], int len)
19 {
20 //--------------------init
21 int max_len = 0;
22 int pos;
23 //--------------------find max length
24 for (int i = 1; i < len; i++) {
25 pos = upper_bound(data, max_len, data[i]);
26 if (pos > max_len) //get longer sequence
27 max_len = pos;
28 data[pos] = data[i]; //modify smallest tail value
29 }
30 //--------------------return
31 return max_len + 1; //due to staring index is 1 not 0
32 }
33
34 int main(int argc, char *argv[])
35 {
36 int test_num;
37 scanf("%d", &test_num);
38 int array_length;
39 //-----------------run each test case
40 for (int i = 0; i < test_num; i++) {
41 //------------------------get input
42 scanf("%d", &array_length);
43 int data[array_length];
44 for (int j = 0; j < array_length; j++) {
45 scanf("%d", &data[j]);
46 }
47 //------------------------print result
48 printf("%d\n", maxIncreasingSequence(data, array_length));
49 }
50 return 0;
51 }
52
53