额(⊙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