[CF1468A] LaIS - dp,树状数组

[CF1468A] LaIS - dp,树状数组

Description

给出一个长度为 \(n\) 的序列 \(a_1,a_2,...,a_n\) ,请找出一个子序列 \(b_1,b_2,...,b_k\) ,使其满足 \(\min(b_1,b_2)\le \min(b_2,b_3)\le ...\le \min(b_{k-1},b_k)\) ,求出 \(k\) 的最大值。

Solution

LaIS 中由一个子序列满足是 IS 并且元素距离不超过 2,称为这个 LaIS 的核

我们考虑对着这个核去 dp

我们按值升序扫描所有元素,设 \(f[i]\) 表示以 \(a[i]\) 为核的结尾的 LaIS 的最大长度

假如现在扫描的是 i,我们需要考虑

  • 以 \(a[i]\) 作为 LaIS 的结尾,并且上一个元素也是核,此时 \(f[i]\) 答案更新为 \(f[1..i-1]\) 中的 max + 1
  • 以 \(a[i]\) 作为 LaIS 的结尾,并且上一个元素不是核,此时我们需要找到 i 之前第一个大于等于 \(a[i]\) 的元素,因为它大于当前扫描值,我们把它作为非核元素,再查询他前面的所有核结尾的最大值,进行转移,因此此时 \(f[i]\) 更新为 \(f[1..pos-1]\) 中的 max + 2

单点修改,前缀查询,用一个树状数组(线段树当然也行)维护即可

#include <bits/stdc++.h>
using namespace std;

#define int long long

struct BITree
{
    int n;
    vector<int> a;

    BITree(int n) : n(n)
    {
        a.resize(n + 2);
    }

    int lowbit(int p)
    {
        return p & (-p);
    }

    void Update(int p, int val)
    {
        while (p <= n)
        {
            a[p] = max(a[p], val);
            p += lowbit(p);
        }
    }

    int Max(int p)
    {
        int ans = 0;
        while (p > 0)
        {
            ans = max(ans, a[p]);
            p -= lowbit(p);
        }
        return ans;
    }
};

void GetNext(int n, const vector<int> &a, vector<int> &nxt)
{
    stack<int> sta;
    for (int i = n; i >= 1; i--)
    {
        while (sta.size() && a[i] >= a[sta.top()])
        {
            nxt[sta.top()] = i;
            sta.pop();
        }
        sta.push(i);
    }
}

void solve()
{
    int n;
    cin >> n;

    vector<int> a(n + 2);
    for (int i = 1; i <= n; i++)
        cin >> a[i];

    vector<int> nxt(n + 2);
    GetNext(n, a, nxt);

    vector<pair<int, int>> seq;
    for (int i = 1; i <= n; i++)
        seq.push_back({a[i], i});

    sort(seq.begin(), seq.end());

    BITree bitree(n);

    for (int _ = 0; _ < n; _++)
    {
        int i = seq[_].second;
        int res = bitree.Max(i - 1) + 1;
        if (nxt[i])
        {
            res = max(res, bitree.Max(nxt[i] - 1) + 2);
        }
        bitree.Update(i, res);
    }

    cout << bitree.Max(n) << endl;
}

signed main()
{
    ios::sync_with_stdio(false);

    int t;
    cin >> t;
    while (t--)
        solve();
}
上一篇:Python爬取国内新冠疫情数据及对其数据提取(2021-01-21)


下一篇:LG P2495 [SDOI2011]消耗战