NYOJ 214 单调递增子序列nlogn

普通的思路是O(n2)的复杂度,这个题的数据量太大,超时,这时候就得用nlogn的复杂度的算法来做,这个算法的主要思想是只保存有效的序列,即最大递增子序列,然后最后得到数组的长度就是最大子序列。比如序列7 8 9 1 2 3 来说, 就是先把第一个数输入到数组中,然后继续输入后面的数,每输入一个数都要和最后一个数比较,因为这时最后一个数一定是有效序列中最大的,如果大于最后一个数,那么就直接将它放到数组的最后就行了,如果不大于最后一个数的话,就找到第一个比他大的数,然后替换它,样例中,先输入进去7, 然后再输入8,因为8 > 7, 所以直接将8放到数组的最后,同理,9也是,当输入到1的时候,判断它不比9大,这时候就需要找第一个比1大的数,这时候就用二分查找就行了,因为这个数组这样输入进去的话,肯定是有序的,找到第一个比他大的数是7,那么就替换7,现在数组中的元素分别是1, 8, 9,继续输入2,判断它不比数组的最后一个元素大,这时候继续二分找第一个比它大的,那么将替换8,同理3将会替换9,最后数组的元素分别是1, 2, 3,这是用贪心的策略来做的,因为只有保存最小的,后面的数组成最长序列的机会才会更大,所以要保存最小的,代码如下;

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <vector>
 5 using namespace std;
 6 const int N = 100000 + 10;
 7 int a[N];//保存当前最大的序列
 8 int e;//表示当前数组中有几个元素
 9 void replace_value(int n)//二分法查找替换
10 {
11     int left = 0, right = e;
12     int mid = (left + right) >> 1;
13     while (left < right)
14     {
15         if (left + 1 == right)
16         {
17             if (a[right] != n)//替换右值
18                 a[right] = n;
19             return;
20
21         }
22         if (a[mid] == n)
23             return;
24         if (a[mid] > n)
25             right = mid;
26         else
27             left = mid;
28         mid = (left + right) >> 1;
29     }
30 }
31 int main()
32 {
33     int n;
34     while (~scanf("%d", &n))
35     {
36         e = 0;
37         memset(a, 0, sizeof(a));
38         a[0] = -2147483648;
39         int t;
40         for (int i = 0; i < n; i++)
41         {
42
43             scanf("%d", &t);
44             if (t > a[e])//如果大于当前已有的数中最大的, 就将它添加到数组中
45                 a[++e] = t;
46             else
47                 replace_value(t);
48         }
49         cout << e << endl;
50     }
51     return 0;
52 }

下面这个代码的思想和上面的基本相同,我是看的网上的,大体思路就是先将数据输入到一个数组中,然后在一个一个的判断,找每个元素应该在的位置,也就是上面的那种思想,不过不如上面的那个简单

 1 #include <stdio.h>
 2
 3 const int N = 100000 + 10;
 4 int a[N], b[N];//a来存放输入的元素,b来存放当前最长子序列元素
 5 //寻找n所在b当中的位置,二分查找,时间复杂度logn;
 6 int search_pos(int n, int len)
 7 {
 8     int left = 1, right = len;
 9     int mid = (left + right) >> 1;
10     while (left <= right)
11     {
12         if (b[mid] == n)
13             return mid;
14         else if (b[mid] < n)
15             left = mid + 1;
16         else
17             right = mid - 1;
18         mid = (left + right) >> 1;
19     }
20     return left;
21 }
22 int main()
23 {
24     int n;
25     while (~scanf("%d", &n))
26     {
27         for (int i = 0; i < n; i++)
28             scanf("%d", &a[i]);
29         b[1] = a[0];
30         int len = 1;
31         int j;
32         for (int i = 1; i < n; i++)
33         {
34             j = search_pos(a[i], len);//找到第一个比他大的位置,如果已经是最大,那么就是b数组的最后一个位置
35             b[j] = a[i];
36             if (j > len)//如果是最后一个位置,len更新为j
37                 len = j;
38         }
39         printf("%d\n", len);
40     }
41     return 0;
42 }
时间: 2024-12-20 13:30:46

NYOJ 214 单调递增子序列nlogn的相关文章

nyoj 214 单调递增子序列(二) 【另类dp】

单调递增子序列(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 给定一整型数列{a1,a2...,an}(0<n<=100000),找出单调递增最长子序列,并求出其长度. 如:1 9 10 5 11 2 13的最长单调递增子序列是1 9 10 11 13,长度为5. 输入 有多组测试数据(<=7) 每组测试数据的第一行是一个整数n表示序列中共有n个整数,随后的下一行里有n个整数,表示数列中的所有元素.每个整形数中间用空格间隔开(0<n<=1

nyoj 214——单调递增子序列(二)——————【二分搜索加dp】

单调递增子序列(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 给定一整型数列{a1,a2...,an}(0<n<=100000),找出单调递增最长子序列,并求出其长度. 如:1 9 10 5 11 2 13的最长单调递增子序列是1 9 10 11 13,长度为5. 输入 有多组测试数据(<=7)每组测试数据的第一行是一个整数n表示序列中共有n个整数,随后的下一行里有n个整数,表示数列中的所有元素.每个整形数中间用空格间隔开(0<n<=10

NYOJ 214 单调递增子序列(二)

单调递增子序列(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 给定一整型数列{a1,a2...,an}(0<n<=100000),找出单调递增最长子序列,并求出其长度. 如:1 9 10 5 11 2 13的最长单调递增子序列是1 9 10 11 13,长度为5. 输入 有多组测试数据(<=7) 每组测试数据的第一行是一个整数n表示序列中共有n个整数,随后的下一行里有n个整数,表示数列中的所有元素.每个整形数中间用空格间隔开(0<n<=1

NYOJ 214 单调递增子序列(二)

#include<stdio.h>#include<string.h>const int maxn=100001;int dp[maxn],a[maxn];int Binary_search(int len,int k){ // 查找比第一个比dp[i]小或者是相等的位置 int start,end,mid; start=1; end=len; while(start<=end) { mid=(start+end)>>1; if(k==dp[mid]) retur

nyist oj 214 单调递增子序列(二) (动态规划经典)

单调递增子序列(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 给定一整型数列{a1,a2...,an}(0<n<=100000),找出单调递增最长子序列,并求出其长度. 如:1 9 10 5 11 2 13的最长单调递增子序列是1 9 10 11 13,长度为5. 输入 有多组测试数据(<=7) 每组测试数据的第一行是一个整数n表示序列中共有n个整数,随后的下一行里有n个整数,表示数列中的所有元素.每个整形数中间用空格间隔开(0<n<=1

南阳ACM~~214单调递增子序列(二)

刚开始做这题的时候,以为是简单的动态规划,后来提交之后发现超时了,看到了N可以达到100000,用简单的动态规划,时间复杂度达到了N^2,明显会超时. 想了挺久的,还是不知道怎么做,百度了一下,才知道了原来运用二分搜索,把问题简化成类似排序,时间复杂度为logN,就不会超时了. 下面是AC的代码,看注释可以很容易理解的.如说的有错,欢迎指正. #include <iostream> #include <stdio.h> #include <cstring> using

NYOJ 214 单调递增最长子序列(二)

#include<stdio.h>#include<string.h>const int max=10001;int dp[max];char s[max];int maxn;void LTCS(){ int len; memset(dp,0,sizeof(dp)); len=strlen(s); for(int i=0;i<len;i++) { dp[i]=1; for(int j=0;j<i;j++) { if(s[i]>s[j] && dp[

nyoj 单调递增子序列(二)

单调递增子序列(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描述 给定一整型数列{a1,a2...,an}(0<n<=100000),找出单调递增最长子序列,并求出其长度. 如:1 9 10 5 11 2 13的最长单调递增子序列是1 9 10 11 13,长度为5. 输入 有多组测试数据(<=7)每组测试数据的第一行是一个整数n表示序列中共有n个整数,随后的下一行里有n个整数,表示数列中的所有元素.每个整形数中间用空格间隔开(0<n<=10

最长单调递增子序列 POJ 3903 Stock Exchange .

题目传送门 : -------->点这里点这里<---------- 题目大意: 给出一串正整数,个数为N个.1<=N<=100000.求最长单调递增子序列长度. 样例输入: 6 5 2 1 4 5 3 3 1 1 1 4 4 3 2 1 样例输出: 3 1 1 =================================================================== 最长单调递增子序列问题的DP朴素算法复杂度为 O(n^2); 然而题目中的 N 最大有