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