九度oj 题目1533:最长上升子序列
- 题目描述:
-
给定一个整型数组, 求这个数组的最长严格递增子序列的长度。 譬如序列1 2 2 4 3 的最长严格递增子序列为1,2,4或1,2,3.他们的长度为3。
- 输入:
-
输入可能包含多个测试案例。
对于每个测试案例,输入的第一行为一个整数n(1<=n<=100000):代表将要输入的序列长度
输入的第二行包括n个整数,代表这个数组中的数字。整数均在int范围内。
- 输出:
-
对于每个测试案例,输出其最长严格递增子序列长度。
- 样例输入:
-
4
4 2 1 3
5
1 1 1 1 1
- 样例输出:
-
2
1 这个题一开始用最简单的办法来做,果然超时了
代码如下#include <cstdio>
int toDo[];
int cnt[]; int n;
int main(int argc, char const *argv[])
{
while(scanf("%d",&n) != EOF) {
for(int i = ; i < n ; i++) {
scanf("%d",&toDo[i]);
}
int max = ;
for(int i = ; i < n; i++) {
int maxi = ;
for(int j = i-; j >= ; j--) {
if(toDo[j] < toDo[i] && maxi < cnt[j]) {
maxi = cnt[j];
}
}
cnt[i] = maxi + ;
if(max < cnt[i]) {
max = cnt[i];
}
}
printf("%d\n",max);
}
return ;
}后来参考了许多别人的博客,才明白应该这样做
首先,你需要一个数组minNum[i]来记录达到长度i的最小数字是几,这个数组必然是递增的,因为长度更长的它的数字肯定更大。
那么,当一个新数字来的时候,假设现在最长的长度为k
如果它比minNum[k]大,那么minNum[++k] = newNum;
如果不比minNum[k]大,则需要去更新这个数组中的元素。具体需采用二分法来找到这个数字的位置,接着更新之。
但一开始提交错误,原来的代码是这样的
#include <cstdio>
int toDo[];
int minNum[]; int n; int bSearch(int p,int low, int high) {
if(low < high) {
int mid = (low + high)/;
if(minNum[mid] == p) {
return mid;
}
else if(minNum[mid] < p) {
return bSearch(p, mid+, high);
}
else {
return bSearch(p, low, mid-);
}
}
return low;
} int main(int argc, char const *argv[])
{
while(scanf("%d",&n) != EOF) {
for(int i = ; i < n ; i++) {
scanf("%d",&toDo[i]);
} minNum[] = toDo[];
int k = ;
for(int i = ; i < n; i++) {
if(toDo[i] > minNum[k]) {
minNum[++k] = toDo[i];
}
else {
int p = bSearch(toDo[i], , k);
minNum[p] = toDo[i];
}
}
printf("%d\n",k);
}
return ;
}经过实验,发现测试数据为 4 5 6 1 2 3 5就会出错,
检查之后发现是二分搜索的错误,当minNum为 1 5 6时, 2 的到来使它变为2 5 6, 而不是1 2 6
修改在17行
代码如下
#include <cstdio>
int toDo[];
int minNum[]; int n; int bSearch(int p,int low, int high) {
if(low < high) {
int mid = (low + high)/;
if(minNum[mid] == p) {
return mid;
}
else if(minNum[mid] < p) {
return bSearch(p, mid+, high);
}
else {
return bSearch(p, low, mid);
}
}
return low;
} int main(int argc, char const *argv[])
{
while(scanf("%d",&n) != EOF) {
for(int i = ; i < n ; i++) {
scanf("%d",&toDo[i]);
} minNum[] = toDo[];
int k = ;
for(int i = ; i < n; i++) {
if(toDo[i] > minNum[k]) {
minNum[++k] = toDo[i];
}
else {
int p = bSearch(toDo[i], , k);
minNum[p] = toDo[i];
}
}
printf("%d\n",k);
}
return ;
}事实上,不需要toDo这个数组,代码如下
#include <cstdio>
int toDo;
int minNum[];
int n; int bSearch(int p,int low, int high) {
if(low < high) {
int mid = (low + high)/;
if(minNum[mid] == p) {
return mid;
}
else if(minNum[mid] < p) {
return bSearch(p, mid+, high);
}
else {
return bSearch(p, low, mid);
}
}
return low;
} int main(int argc, char const *argv[])
{
while(scanf("%d",&n) != EOF) {
int k = ;
for(int i = ; i < n ; i++) {
scanf("%d",&toDo);
if(k == ) {
minNum[++k] = toDo;
continue;
}
if(toDo > minNum[k]) {
minNum[++k] = toDo;
}
else {
int p = bSearch(toDo, , k);
minNum[p] = toDo;
}
}
printf("%d\n",k);
}
return ;
}今天看书,知道有个函数是lower_band(), upper_band(),fill();
需要#include <algorithm>
using namespace std
lower_band()从已排好序的序列a中利用二分搜索(区间左开右闭)找出指向满足ai>=k的ai的最小指针
lower_band(a, a+n, k)
可以写出如下代码
#include <cstdio>
#include <algorithm>
using namespace std;
int toDo;
int dp[];
int n; int main(int argc, char const *argv[])
{
while(scanf("%d",&n) != EOF) {
int k = ;
for(int i = ; i < n ; i++) {
scanf("%d",&toDo);
if(k == ) {
dp[k++] = toDo;
}
else {
int *p = lower_bound(dp,dp+k,toDo);
if(p - dp == k) {
dp[k++] = toDo;
}
else {
*p = toDo;
}
} } printf("%d\n",k);
}
return ;
}甚至是
#include <cstdio>
#include <algorithm>
#define inf 2147483647
using namespace std;
int toDo;
int dp[];
int n; int main(int argc, char const *argv[])
{
while(scanf("%d",&n) != EOF) {
int k = ;
fill(dp, dp+n,inf);
for(int i = ; i < n ; i++) {
scanf("%d",&toDo);
*lower_bound(dp,dp+n,toDo) = toDo;
} printf("%d\n",lower_bound(dp, dp+n, inf) - dp);
}
return ;
}
九度oj 题目1533:最长上升子序列的更多相关文章
- 九度OJ 题目1384:二维数组中的查找
/********************************* * 日期:2013-10-11 * 作者:SJF0115 * 题号: 九度OJ 题目1384:二维数组中的查找 * 来源:http ...
- hdu 1284 关于钱币兑换的一系列问题 九度oj 题目1408:吃豆机器人
钱币兑换问题 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Sub ...
- 九度oj题目&吉大考研11年机试题全解
九度oj题目(吉大考研11年机试题全解) 吉大考研机试2011年题目: 题目一(jobdu1105:字符串的反码). http://ac.jobdu.com/problem.php?pid=11 ...
- 九度oj 题目1007:奥运排序问题
九度oj 题目1007:奥运排序问题 恢复 题目描述: 按要求,给国家进行排名. 输入: 有多组数据. 第一行给出国家数N,要求排名的国家数M,国家号 ...
- 九度oj 题目1087:约数的个数
题目链接:http://ac.jobdu.com/problem.php?pid=1087 题目描述: 输入n个整数,依次输出每个数的约数的个数 输入: 输入的第一行为N,即数组的个数(N<=1 ...
- 九度OJ题目1105:字符串的反码
tips:scanf,cin输入字符串遇到空格就停止,所以想输入一行字符并保留最后的"\0"还是用gets()函数比较好,九度OJ真操蛋,true?没有这个关键字,还是用1吧,还是 ...
- 九度oj题目1009:二叉搜索树
题目描述: 判断两序列是否为同一二叉搜索树序列 输入: 开始一个数n,(1<=n<=20) 表示有n个需要判断,n= 0 的时候输入结束. 接 ...
- 九度oj题目1002:Grading
//不是说C语言就是C++的子集么,为毛printf在九度OJ上不能通过编译,abs还不支持参数为整型的abs()重载 //C++比较正确的做法是#include<cmath.h>,cou ...
- 九度OJ题目1003:A+B
while(cin>>str1>>str2)就行了,多简单,不得不吐槽,九度的OJ真奇葩 题目描述: 给定两个整数A和B,其表示形式是:从个位开始,每三位数用逗号", ...
随机推荐
- SSM环境集成log4j
本文只针对非Maven环境: 1.拷入log4j相关的.jar 2.在web.xml中配置 <!--由Spring载入的Log4j配置文件位置--> <context-param&g ...
- .NET Core 1.0 CentOS7 尝试(二、VSCode安装)
晚上继续摸索~~ 一.VSCode安装 下载VSCode,地址:https://code.visualstudio.com/Docs/?dv=linux64_rpm 直接双击安装或者使用rpm -i ...
- ef导航属性
https://msdn.microsoft.com/en-us/data/jj574232.aspx 场景是 A表中有B,B表中又C.都是一堆多的关系.怎样Mapping是个问题啊. var ...
- selenium的定位
id定位 find_element_by_id()方法通过id来定位元素 例如: find_element_by_id("kw") find_element_by_id(&quo ...
- 系统妈Win10系统64位和32位快速专业版
win10系统64位快速专业安装版 V2016年 系统妈:http://www.xitongma.com/ Ghost Win10 64位正式装机专业版2016 微软向Windows用户推送了win1 ...
- UVA 1664 Conquer a New Region (Kruskal,贪心)
题意:在一颗树上要求一个到其他结点容量和最大的点,i,j之前的容量定义为i到j的路径上的最小边容量. 一开始想过由小到大的去分割边,但是很难实现,其实换个顺序就很容易做了,类似kruskal的一个贪心 ...
- block总结我的
1) struct Block_descriptor { unsigned long int reserved; unsigned long int size; void (*copy)(void * ...
- The - Modcrab——使用贪心策略
一.题目信息 The - Modcrab 简单翻译一下:Vova有生命值h1,每次攻击值为a1,每瓶药水恢复生命值c1;Modcrab有生命值h2,每次攻击值为a2.在每个关卡开始,Vova有两种选择 ...
- c++ 中的函数调用中的参数传递
概述 初学 \(c++\),一直搞不懂其参数传递方式.故找到一篇不错的文章:刘志华的深入探讨C++语言中参数传递问题.亲自实践一遍,并作此记录,以加深印象. 主要内容 本文主要分为五个小部分, ...
- 公共Service的抽取小例
package cn.sxx.service; import java.util.List; public interface BaseService<T,Q> { public void ...