LIS 1.LIS+数据结构 2.LIS覆盖问题+爆搜
友好城市 https://www.acwing.com/problem/content/1014/
画一条河的上下两岸 建桥 要求不能交叉 问最多建立多少道桥
转化成对于任何下河道的桥 转化为数组下表 上河道第几个桥变成数组的值 那么就是看LIS的值
数据给出一对值 如果不能保证单调上升说明这么做不行 使用PII 来做
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 5005;
typedef pair<int, int> PII;
PII q[N];
#define x first
#define y second
int f[N];
int main()
{
int n;
cin >> n;
for (int i = 0; i < n; i ++ ){
cin >> q[i].x>>q[i].y;
}
sort(q,q+n);//需要排序 保证下标的是升序
int res=0;
for (int i = 0; i < n; i ++ ){
f[i]=1;
for (int j = 0; j < i; j ++ ){
if(q[i].y>q[j].y)
f[i]=max(f[i],f[j]+1);
}
res=max(res,f[i]);
}
cout << res;
return 0;
}
最大上升子序列 求上升子序列的和的最大值
int main()
{
int res=0;
int n;cin>>n;
for (int i = 0; i < n; i ++ ){
cin>>q[i];
}
// int c=0;
for (int i = 0; i < n; i ++ ){
f[i]=q[i];
for (int j = 0; j < i; j ++ ){
if(q[i]>q[j])
f[i]=max(f[i],f[j]+q[i]);
}
res=max(res,f[i]);
}
cout << res;
return 0;
}
离散化 +树状数组 +LIS 强化版本最大子序列
最大上升子序列和
需要查询
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long LL;
const int N = 100010;
int n;
int w[N];
LL tr[N];
vector<int> xs;
LL f[N];
int get(int x)
{
return lower_bound(xs.begin(), xs.end(), x) - xs.begin() + 1;//存是在0开始存的 但返回的时候是1开始返回的
}
int lowbit(int x)
{
return x & -x;
}
void add(int x, LL v)
{
for (int i = x; i <= n; i += lowbit(i))
tr[i] = max(tr[i], v);
}
LL query(int x)
{
LL res = 0;
for (int i = x; i; i -= lowbit(i))
res = max(res, tr[i]);
return res;
}
int main()
{
scanf("%d", &n);
for (int i = 0; i < n; i ++ )
{
scanf("%d", &w[i]);
xs.push_back(w[i]);//保存所有存储的元素
}
sort(xs.begin(), xs.end());//将所有元素大小排序
xs.erase(unique(xs.begin(), xs.end()), xs.end());//删除重复的元素 这里的xs还是存的元素而不是下表 用于find的找
LL res = 0;
for (int i = 0; i < n; i ++ )//这里的数是n个a数组
{
int k = get(w[i]);//找到w[i]元素在xs数组对应的映射的下标
f[i] = query(k - 1) + w[i];//query查询xs的下标
res = max(res, f[i]);//更新最大值
add(k, f[i]);//在tr第k个位置插入
}
printf("%lld\n", res);
return 0;
}
LIS覆盖序列
问给定一个数列 最少可用多少组最长上升子序列去放好所有数字
贪心做法 多开几个序列 最后一个值是每个序列里的最小值 对于数组的每个值 查看下每个序列的最后一个值是否比他小 是的话就放进去 不然的话 只能新开一个序列 最终答案是已经开的序列的值
int cnt=0;
for (int i = 0; i < n; i ++ ){
int k=0;
while ( k<cnt&&g[k]<q[i] ) k++;//
g[k]=q[i];
if(k>=cnt) cnt++;
}
cout << cnt;//cnt
https://www.acwing.com/problem/content/189/