额(⊙o⊙)… 先放题目链接
题目传送门:https://vjudge.net/problem/POJ-1631
题目就是求最长上升序列(自己想想吧!)
lis是啥——>一个数的序列bi,当b1 < b2 < … < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, …, aN),我们可以得到一些上升的子序列(ai1, ai2, …, aiK),这里1 <= i1 < i2 < … < iK <= N。比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8).
测试数据(题目上给的太扯犊子了)
Sample Input
4
6
4 2 6 3 1 5
10
2 3 4 5 6 7 8 9 10 1
8
8 7 6 5 4 3 2 1
9
5 8 9 2 3 1 7 4 6
Sample Output
3
9
1
4
这样多好看,真是的!^_^
首先
我们来看一种方法:大致运用dp来做的
直接上代码,学过一点点dp的估计都看的懂!不懂就留言吧!
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#define N 40005
using namespace std;
int a[N];
int dp[N];
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
int mmax = -1;
for(int i = 1; i <= n; i++)
{
dp[i] = 1;
for(int j = 1; j <= i; j++)
{
if(a[i] > a[j] && dp[i] < dp[j] + 1)
dp[i] = dp[j] + 1;
}
mmax = max(mmax, dp[i]);
}
printf("%d\n", mmax);
}
return 0;
}
估计会有人直接去提交,我可没说是ac的代码,这是tl的代码,其实一看,就知道超时 一个for和两个for嵌套,肯定的
(・ω・`ll),复杂度为n^2
换方法吧!先上代码^_^
#include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <cmath> #include <queue> #include <set> #include <map> #define N 40005 using namespace std; int a[N]; int dp[N]; int main() { int T; scanf("%d", &T); while(T--) { int n; scanf("%d", &n); for(int i = 1; i <= n; i++) scanf("%d", &a[i]); int len = 1; dp[1] = a[1]; for(int i = 2; i <= n; i++) { if(a[i] > dp[len]) { len++; dp[len] = a[i]; continue; } int l = 1, r = len; while(l <= r) { int mid = (l + r) / 2; if(dp[mid] > a[i]) r = mid - 1; else l = mid + 1; } dp[l] = a[i]; } printf("%d\n", len); } return 0; }
首先
len = 1,dp[1] = a[1],然后对a[i]:若a[i]>dp[len],那么len++,dp[len] = a[i];
否则
我们要从d[1]到dp[len-1]中找到一个j,满足dp[j-1]<a[i]<d[j]
则
根据D的定义,我们需要更新长度为j的上升子序列的最末元素(使之为最小的)即 dp[j] = a[i];
最终
答案就是len
利用dp的单调性,在查找j的时候可以二分查找,从而时间复杂度为n*logn
再看一个用stl写的
#include <cstdio> #include <cstring> #include <iostream> #include <cmath> #include<vector> #include<queue> #include<algorithm> using namespace std; typedef long long LL; const int maxn=500009; const int INF=0x3f3f3f3f; int n; int a[maxn]; int dp[maxn]; int main() { int T; scanf("%d", &T); while(T--) { scanf("%d", &n); for(int i=1; i<=n; i++) scanf("%d", &a[i]); dp[0]=0; int len=0; for(int i=1; i<=n; i++) { if(a[i]>dp[len]) { dp[++len]=a[i]; continue; } int t=upper_bound(dp, dp+len, a[i])-s; dp[t]=a[i]; } printf("%d\n", len); } return 0; }
函数具体,看大牛的博客吧!
http://www.cnblogs.com/cobbliu/archive/2012/05/21/2512249.html
好
了
这
就
结
束
了
吗
!
好吧!没有,最近在学习树状数组,忽然我……………………………………
在网上看到了,一个用来树状数组写的,还不错就打了一遍!
不解释,想看就看,不看也无关!
#include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <cmath> #include <queue> #include <set> #include <map> #define N 40005 #define MAX 0x3f3f3f3f using namespace std; struct point { int num, x; }a[N]; int dp[N], n; bool comp(point a, point b) { if(a.num == b.num) return a.x < b.x; return a.num < b.num; } int lowbit(int x) { return x & (-x); } int find(int x) { int ret = -MAX; while(x) { ret = max(ret, dp[x]); x -= lowbit(x); } return ret; } void change(int x ,int y) { while(x <= n) { dp[x] = max(dp[x], y); x += lowbit(x); } } int main() { int T; scanf("%d", &T); while(T--) { memset(dp, 0, sizeof(dp)); scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%d", &a[i].num); a[i].x = i; } sort(a + 1, a + n + 1, comp); int ans = 0; for(int i = 1; i <= n; i++) { int mmax = find(a[i].x); change(a[i].x, ++mmax); ans = max(ans, mmax); } printf("%d\n", ans); } return 0; }
最后,推荐一个博客吧!讲了三种解决方法(写的很好,但是感觉没必要)
http://blog.csdn.net/george__yu/article/details/75896330#reply