加载中...

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/


posted @ 2022-05-20 19:22  liang302  阅读(88)  评论(0编辑  收藏  举报