首页 > 其他分享 >P4093 [HEOI2016/TJOI2016] 序列 题解

P4093 [HEOI2016/TJOI2016] 序列 题解

时间:2024-01-10 17:25:11浏览次数:39  
标签:node val int 题解 P4093 TJOI2016 include dp define

题目链接:序列

对于 LIS 问题,很显而易见的有 dp方程为:

\[dp_i=\max{dp_j}+1 \ (j<i,a_j \le a_i) \text{ dp表示以某个位置结尾的最长 LIS} \]

本题考虑到对于转移的两位置,如果能从 \(j \rightarrow i\),那么在以上条件成立的基础情况下,我们由于可以更改二者中的任意一个值(因为同一时刻只能更改一个值),所以如果更改前者那么要保证更改后满足 \(max_j \le a_i\),依旧满足上述的对应关系。如果更改的是 \(i\) 位置的数,保证更改后也满足 \(a_j \le min_i\) 。(因为题目说的是任意一种变化,我们只需要考虑极端的变化即可)。那么转移方程 (\(dp_j \rightarrow dp_i\)) 的条件就为:

  1. \(j < i\)

  2. \(max_j \le a_i\)

  3. \(a_j \le min_i\)

很显而易见,偏序问题,用 cdq 分治来做。注意到 dp 是从左往右,自带有序,所以我们 cdq 分治也应该从原有的两边合并转化为优先处理完左侧的数据再更新右侧数据,类似于二叉树先遍历完左子树。

细节

稍微注意一下,在排序时,我们不应该直接对两侧状态进行排序,因为我们是先遍历左半边的,再遍历右半边的,但遍历左半边对右半边的影响时,排序时会排序右半边导致右半边的 dp 状态量不再是从左往右了,导致遍历右半边时更新错误,所以应该开一个存取相对位置的下标数组进行排序而不影响原数组。

另外注意到我们的偏序条件,左边是 \(max_j\) 右边是 \(val_i\),所以左右两边排序条件的关键字是不一样的。查询我们可以考虑使用树状数组查询 \(val_j \le min_i\) 的 \(\max{dp_j}\) 用于更新当前的 \(dp_i\)。(值域 \(min_i,val_i\le n\))

参照代码
#include <bits/stdc++.h>

//#pragma GCC optimize("Ofast,unroll-loops")

#define isPbdsFile

#ifdef isPbdsFile

#include <bits/extc++.h>

#else

#include <ext/pb_ds/priority_queue.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/trie_policy.hpp>
#include <ext/pb_ds/tag_and_trait.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/list_update_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/exception.hpp>
#include <ext/rope>

#endif

using namespace std;
using namespace __gnu_cxx;
using namespace __gnu_pbds;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef tuple<int, int, int> tii;
typedef tuple<ll, ll, ll> tll;
typedef unsigned int ui;
typedef unsigned long long ull;
typedef __int128 i128;
#define hash1 unordered_map
#define hash2 gp_hash_table
#define hash3 cc_hash_table
#define stdHeap std::priority_queue
#define pbdsHeap __gnu_pbds::priority_queue
#define sortArr(a, n) sort(a+1,a+n+1)
#define all(v) v.begin(),v.end()
#define yes cout<<"YES"
#define no cout<<"NO"
#define Spider ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
#define MyFile freopen("..\\input.txt", "r", stdin),freopen("..\\output.txt", "w", stdout);
#define forn(i, a, b) for(int i = a; i <= b; i++)
#define forv(i, a, b) for(int i=a;i>=b;i--)
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define endl '\n'
//用于Miller-Rabin
[[maybe_unused]] static int Prime_Number[13] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37};

template <typename T>
int disc(T* a, int n)
{
    return unique(a + 1, a + n + 1) - (a + 1);
}

template <typename T>
T lowBit(T x)
{
    return x & -x;
}

template <typename T>
T Rand(T l, T r)
{
    static mt19937 Rand(time(nullptr));
    uniform_int_distribution<T> dis(l, r);
    return dis(Rand);
}

template <typename T1, typename T2>
T1 modt(T1 a, T2 b)
{
    return (a % b + b) % b;
}

template <typename T1, typename T2, typename T3>
T1 qPow(T1 a, T2 b, T3 c)
{
    a %= c;
    T1 ans = 1;
    for (; b; b >>= 1, (a *= a) %= c)if (b & 1)(ans *= a) %= c;
    return modt(ans, c);
}

template <typename T>
void read(T& x)
{
    x = 0;
    T sign = 1;
    char ch = getchar();
    while (!isdigit(ch))
    {
        if (ch == '-')sign = -1;
        ch = getchar();
    }
    while (isdigit(ch))
    {
        x = (x << 3) + (x << 1) + (ch ^ 48);
        ch = getchar();
    }
    x *= sign;
}

template <typename T, typename... U>
void read(T& x, U&... y)
{
    read(x);
    read(y...);
}

template <typename T>
void write(T x)
{
    if (typeid(x) == typeid(char))return;
    if (x < 0)x = -x, putchar('-');
    if (x > 9)write(x / 10);
    putchar(x % 10 ^ 48);
}

template <typename C, typename T, typename... U>
void write(C c, T x, U... y)
{
    write(x), putchar(c);
    write(c, y...);
}


template <typename T11, typename T22, typename T33>
struct T3
{
    T11 one;
    T22 tow;
    T33 three;

    bool operator<(const T3 other) const
    {
        if (one == other.one)
        {
            if (tow == other.tow)return three < other.three;
            return tow < other.tow;
        }
        return one < other.one;
    }

    T3() { one = tow = three = 0; }

    T3(T11 one, T22 tow, T33 three) : one(one), tow(tow), three(three)
    {
    }
};

template <typename T1, typename T2>
void uMax(T1& x, T2 y)
{
    if (x < y)x = y;
}

template <typename T1, typename T2>
void uMin(T1& x, T2 y)
{
    if (x > y)x = y;
}

constexpr int N = 1e5 + 10;

struct DP
{
    int val, max, min, dp;

    bool operator<(const DP& other) const
    {
        return dp < other.dp;
    }
} node[N];

int n, m;
int bit[N];

inline void add(int x, const int val)
{
    while (x <= n)uMax(bit[x], val), x += lowBit(x);
}

inline void clear(int x)
{
    while (x <= n)bit[x] = 0, x += lowBit(x);
}

inline int query(int x)
{
    int ans = 0;
    while (x)uMax(ans, bit[x]), x -= lowBit(x);
    return ans;
}

int pos[N]; //拷贝一份地址数组

inline void cdq(const int L, const int R)
{
    const int mid = L + R >> 1;
    if (L == R)return;
    cdq(L, mid);
    forn(i, L, R)pos[i] = i;
    stable_sort(pos + L, pos + mid + 1, [&](const int i, const int j)
    {
        return node[i].max < node[j].max;
    });
    stable_sort(pos + mid + 1, pos + R + 1, [&](const int i, const int j)
    {
        return node[i].val < node[j].val;
    });
    int l = L;
    forn(r, mid+1, R)
    {
        while (l <= mid and node[pos[l]].max <= node[pos[r]].val)add(node[pos[l]].val, node[pos[l]].dp), l++;
        uMax(node[pos[r]].dp, query(node[pos[r]].min) + 1);
    }
    forn(i, L, mid)clear(node[i].val);
    cdq(mid + 1, R);
}

inline void solve()
{
    cin >> n >> m;
    forn(i, 1, n)
    {
        cin >> node[i].val;
        node[i].max = node[i].min = node[i].val;
        node[i].dp = 1;
    }
    forn(i, 1, m)
    {
        int pos, val;
        cin >> pos >> val;
        uMax(node[pos].max, val);
        uMin(node[pos].min, val);
    }
    cdq(1, n);
    cout << max_element(node + 1, node + n + 1)->dp;
}

signed int main()
{
    Spider
    //------------------------------------------------------
    int test = 1;
    //    read(test);
    // cin >> test;
    forn(i, 1, test)solve();
    //    while (cin >> n, n)solve();
    //    while (cin >> test)solve();
}

\[时间复杂度为 O(n\log^2{n}) \]

标签:node,val,int,题解,P4093,TJOI2016,include,dp,define
From: https://www.cnblogs.com/Athanasy/p/17956917

相关文章

  • 2023 百度之星决赛题解
    T4传信游戏建反向边,从入度为\(0\)的结点开始搜T5喵喵卫士,全靠你了\(\star\)考虑暴力枚举每个点的深度,发现只要知道相邻两层的深度就能用组合数算方案数,自然想到按层DP,把上一层的点数记到状态里赛时做法按深度从小到大DP的话想要记录每个点是否被用过,以保证深度达到上......
  • P3203 弹飞绵羊 题解
    QuestionP3203[HNOI2010]弹飞绵羊一条直线上摆着\(n\)个弹簧,每个弹簧有一个弹力系数\(k_i\),当绵羊走到第\(i\)个弹簧时,会被弹到第\(i+k_i\)个弹簧,如果\(i+k_i>n\)则会被弹飞,有两个操作1x查询\(x\)处的绵羊经过几次会被弹飞2xy把\(x\)处的弹力系数改成......
  • P1307题解
    思路1.定义及输入原数/反转后的数intn,cnt=0;//反转后的数一定要归零!cin>>n;2.用while循环反转while(n!=0){//只要n还没有被分解完,就继续分解cnt=cnt*10+n%10;//cnt每次*10再加上分离出的数位(*10为了防0)n/=10;//n减一位}3.输出cout<<cnt;至此,这道题就做完......
  • P5722题解
    说两句哈,等差数列求和公式是\((A_1+A_n)\timesd\over2\),所以其实可以一行代码解决,但是我没高斯聪明,于是我不打算用等差数列求和公式。//(等差数列求和公式)intn;cin>>n;cout<<(1+n)*1/2;思路1.定义及输入截止的数/计数器intn,cnt=0;//计数器必须归零!cin>>n;2.循环......
  • P1085题解
    思路1.定义校内时间/校外时间/最大值(记录不高兴值)/记录星期intn,m,maxx=-1,tmp;2.使用循环输入并判断for(inti=1;i<=7;i++){//循环一周的日期cin>>n>>m;if(n+m>8&&maxx<n+m){//如果津津不高兴了且它比以往的值都大maxx=n+m;//更改最大值tmp=i;......
  • P5718题解
    思路1.定义及输入最小值的变量/输入个数/每个数intn,m,minn=1001;cin>>n;2.循环输入每个数并找最小值while(n--){cin>>m;minn=min(minn,m);}(用for循环也可以)for(inti=1;i<=n;i++){cin>>m;minn=min(minn,m);}3.输出cout<<minn;至此,这道题就做......
  • 堆算法题解
    输入一个长度为n的整数数列,从小到大输出前m小的数。输入格式第一行包含整数n和m。第二行包含n个整数,表示整数数列。输出格式共—行,包含m个整数,表示整数数列中前m小的数。数据范围1≤m≤n≤10^51≤数列中元素≤10输入样例:5345132输出样例:123代码:#include<iostream>......
  • ABC335E题解
    洛谷题面感觉有点毒瘤,不过还是有些trick在的。题意翻译(复制于洛谷题面):给定一个\(N\)个点\(M\)条无向边的图,图上每个点都有其颜色。求所有经过点权单调不降的路径中,出现的不同颜色的个数最多是多少。由于是单调不降的路径,所以可以点权大的点到点权小的点的路径对结果没......
  • 复旦大学2023--2024学年第一学期(23级)高等代数I期末考试第七大题解答
    七、(10分) 设$A$为$n\,(n>1)$阶非异阵,$B$是$A$的逆阵. 任取$r$个指标$1\leqi_1<i_2<\cdots<i_r\leqn$, 剩余的指标记为$1\leqi_{r+1}<\cdots<i_n\leqn$.证明:$$|A|\cdotB\begin{pmatrix} i_1&i_2&\cdots&i_r\\ i_1&i_2&......
  • IOS移动端,表单input聚焦时页面放大的问题解析以及解决办法
    在移动端开发H5项目中,发现页面在使用iPhone访问的时候,点击input和textarea等文本输入框聚焦focus()时,页面会整体放大,而且失去焦点之后页面不能返回原来的样子。原因:苹果系统觉得点击输入框放大是一个“很好”的体验,就擅自把页面给放大了,触发机制,IOS端input字体应大于15px,否......