学习C++从娃娃抓起!记录下在AcWing算法基础课中打卡题目,记录每一个瞬间。
附上汇总贴:AcWing算法基础课打卡 | 汇总
【题目描述】
给定一个长度为 N N N 的数列,求数值严格单调递增的子序列的长度最长是多少。
【输入】
第一行包含整数 N N N。
第二行包含 N N N 个整数,表示完整序列。
【输出】
输出一个整数,表示最大长度。
【输入样例】
7
3 1 2 1 8 5 6
【输出样例】
4
【分析】
本题数据规模是10万,不能用动态规划(数据规模1000左右)
1.贪心策略:
(1)q[i]:上升序列长度为i,最后一个数为q[i],要长度最大,末端应最小值,len上升序列最大长度。
(2)a[i]保证以a[i]结尾的上升序列最长。在q[0]-q[len]找最右的点 A,q[A]<a[i],最长上升序列为…q[A] a[i]。
2.二分查找,上升序列中最后一个比a[i]小的点即分界点A,二分返回r,q[r+1]=a[i],形成以a[i]结尾的新的上升序列。上升序列长len=r+1,len上升序列长度最大值。
3.样例。初始q[i]=0,上升序列长len = 0
(1)a[1]=3 → r=0,q[0]=0,q[1]=3,len=1
(2)a[2]=1 → r=0,q[0]=0,q[1]=1,len=1
(3)a[3]=2 → r=1,q[0]=0,q[1]=1,q[2]=2,len=2
(4)a[4]=1 → r=0,q[0]=0,q[1]=1,q[2]=2,len=2
(5)a[5]=8 → r=2,q[0]=0,q[1]=1,q[2]=2,q[3]=8,len=3
(6)a[6]=5 → r=2,q[0]=0,q[1]=1,q[2]=2,q[3]=5,len=3
(7)a[7]=6 → r=3,q[0]=0,q[1]=1,q[2]=2,q[3]=5,q[4]=6,len=4
4.len上升序列长度最大值。保证上升序列长度为i,序列末端值最小,最小值存入q[i]:
(1)若q[1]=x;序列中下一个数y,如果y<x,则替换q[1]=y → 长度为1的序列末端值最小。
(2)当y>x时,上升序列长度+1,q[2]=y,则q[1]<q[2] → q[ ]值递增
(3)当前状态q[1]=x,q[2]=y,q[1]<q[2],序列中下一个数z
(4)如果z<x<y,则q[ ]数组中大于z的只有q[0]=0;则q[0+1]=q[1]=z;q[0]<q[1]<q[2] → 长度为1的序列末端值最小,q[ ]值递增
(5)如果z>x>y,则q[ ]数组中q[2]>y,q[3]=z,q[0]<q[1]<q[2]<q[3]
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int n;
int a[N];
int q[N]; //q[i]上升序列长度为i,序列末端最小值为q[i]
int main()
{
cin >> n;
for (int i=0; i<n; i++) cin >> a[i]; // 读入序列
int len = 0; // 已经求出的最大上升序列长度
for (int i=0; i<n; i++) {
int l=0, r=len;
while (l<r) {
int mid = (l+r+1)/2;
if (q[mid]<a[i]) l=mid;
else r=mid-1;
}
q[r+1] = a[i];
len = max(len, r+1);
}
cout << len << endl;
return 0;
}
【运行结果】
7
3 1 2 1 8 5 6
4