模板题:
AcWing 1017. 怪盗基德的滑翔翼(做两次二分的优化就行)
AcWing 1014. 登山
f
[
i
]
[
0
]
表
示
到
第
i
个
点
,
一
直
上
升
的
最
大
长
度
f[i][0]表示到第i个点,一直上升的最大长度
f[i][0]表示到第i个点,一直上升的最大长度
f
[
i
]
[
1
]
表
示
到
第
i
个
点
,
有
下
降
段
的
最
大
长
度
f[i][1]表示到第i个点,有下降段的最大长度
f[i][1]表示到第i个点,有下降段的最大长度
注意
f
[
i
]
[
j
]
f[i][j]
f[i][j]的转移方程,$
f
[
i
]
[
1
]
f[i][1]
f[i][1]的转移要对
f
[
j
]
[
0
]
和
f
[
j
]
[
1
]
都
要
取
m
a
x
f[j][0]和f[j][1]都要取max
f[j][0]和f[j][1]都要取max
核心代码如下:
int main()
{
int res = -1;
cin >> N;
for (int i = 1; i <= N; ++i)
{
cin >> h[i];
f[i][0] = f[i][1] = 1;
for (int j = 1; j < i; ++j)
{
if (h[j] < h[i])f[i][0] = max(f[i][0], f[j][0] + 1);
if (h[j] > h[i])f[i][1] = max({f[i][1], f[j][0] + 1, f[j][1] + 1});
}
res = max({res, f[i][0], f[i][1]});
}
cout << res;
return 0;
}
AcWing 482. 合唱队形 这道题和上道题一模一样
AcWing 1012. 友好城市 这道题先排序,再求最长上升子序列
AcWing 1016. 最大上升子序列和 暴力直接做,维护一个dp
AcWing 1010. 拦截导弹维护两个序列就行,一个维护最长上升子序列,另一个维护个数(这个序列是单调递增的),用二分做
AcWing 187. 导弹防御系统 这道题有点难感觉,具体来说就是迭代加深,然后把每个数分别讨论放在上升子序列和下降子序列中。迭代加深模板如下:
{
depth = 0;
while (!DFS(1, 0, 0)) ++depth;
cout << depth << '\n';
}
整道题代码如下:
#include <iostream>
using namespace std;
const int N = 55;
int n, a[N], up[N], down[N], depth;
bool DFS(int u, int sum_up, int sum_down)
{
if (sum_up + sum_down > depth)
return false;
if (u == n + 1)
return true;
int k = 0;
while (k < sum_up && up[k] >= a[u])
++k;
int t = up[k];
up[k] = a[u];
if (k == sum_up && DFS(u + 1, sum_up + 1, sum_down))//需要新开
return true;
else if (k < sum_up && DFS(u + 1, sum_up, sum_down))//不需要新开
return true;
up[k] = t;
k = 0;
while (k < sum_down && down[k] <= a[u])
++k;
t = down[k];
down[k] = a[u];
if (k == sum_down && DFS(u + 1, sum_up, sum_down + 1))//需要新开
return true;
else if (k < sum_down && DFS(u + 1, sum_up, sum_down))
return true;
down[k] = t;
return false;
}
int main()
{
while (cin >> n && n)
{
for (int i = 1 ; i <= n ; ++i)cin >> a[i];
depth = 0;
while (!DFS(1, 0, 0)) ++depth;
printf("%d\n", depth);
}
return 0;
}
AcWing 272. 最长公共上升子序列
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示
A
[
1
−
i
]
A[1-i]
A[1−i]与
B
[
1
−
j
]
B[1- j ]
B[1−j]中以
b
[
j
]
b[j]
b[j]结尾的最长公共上升子序列的最大长度,将集合分为不存在
a
[
i
]
a[i]
a[i]和存在
a
[
i
]
a[i]
a[i]的两个集合
前者是
f
[
i
]
[
j
]
=
f
[
i
−
1
]
[
j
]
f[i][j]=f[i-1][j]
f[i][j]=f[i−1][j]
后者的集合又可以分为倒数第二个数分别是
b
[
1
]
,
b
[
2
]
⋅
⋅
⋅
b
[
j
−
1
]
b[1],b[2]···b[j-1]
b[1],b[2]⋅⋅⋅b[j−1]结尾的最长公共上升子序列的长度
下面这是优化前的版本,会
T
L
E
TLE
TLE
for(int i = 1; i <= N; ++i)
{
for(int j = 1; j <= N; ++j)
{
f[i][j] = f[i - 1][j];//a[i]不包含在里面
//下面是a[i]包含在里面
if(A[i] == B[j])
{
int maxv = 1;
for(int k = 1; k < j; ++k)
{
if(B[k] < B[j])
maxv = max(maxv, f[i - 1][k] + 1);
}
f[i][j] = max(f[i][j], maxv);
}
}
}
作者:北极汪汪熊
链接:https://www.acwing.com/activity/content/code/content/2060385/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
下面是优化后的版本,因为
m
a
x
v
maxv
maxv是一个前缀最大值
‘
在
这
里
插
入
代
码
片
‘
`在这里插入代码片`
‘在这里插入代码片‘
for(int i = 1; i <= N; ++i)
{
int maxv=1;
for(int j = 1; j <= N; ++j)
{
f[i][j] = f[i - 1][j];//a[i]不包含在里面
if(A[i]>B[j])
maxv=max(maxv,f[i-1][j]+1);
//下面是a[i]包含在里面
if(A[i] == B[j])
f[i][j]=max(f[i][j],maxv);
}
}
作者:北极汪汪熊
链接:https://www.acwing.com/activity/content/code/content/2060385/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。