(nlogn求LIS,确定状态唯一性)LIS of Sequence CodeForces - 486E

2024-04-16 03:32

本文主要是介绍(nlogn求LIS,确定状态唯一性)LIS of Sequence CodeForces - 486E,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

The next “Data Structures and Algorithms” lesson will be about Longest Increasing Subsequence (LIS for short) of a sequence. For better understanding, Nam decided to learn it a few days before the lesson.

Nam created a sequence a consisting of n (1 ≤ n ≤ 105) elements a1, a2, …, an (1 ≤ ai ≤ 105). A subsequence ai1, ai2, …, aik where 1 ≤ i1 < i2 < … < ik ≤ n is called increasing if ai1 < ai2 < ai3 < … < aik. An increasing subsequence is called longest if it has maximum length among all increasing subsequences.

Nam realizes that a sequence may have several longest increasing subsequences. Hence, he divides all indexes i (1 ≤ i ≤ n), into three groups:

group of all i such that ai belongs to no longest increasing subsequences.
group of all i such that ai belongs to at least one but not every longest increasing subsequence.
group of all i such that ai belongs to every longest increasing subsequence.
Since the number of longest increasing subsequences of a may be very large, categorizing process is very difficult. Your task is to help him finish this job.

Input
The first line contains the single integer n (1 ≤ n ≤ 105) denoting the number of elements of sequence a.

The second line contains n space-separated integers a1, a2, …, an (1 ≤ ai ≤ 105).

Output
Print a string consisting of n characters. i-th character should be ‘1’, ‘2’ or ‘3’ depending on which group among listed above index i belongs to.

Examples
Input
1
4
Output
3
Input
4
1 3 2 5
Output
3223
Input
4
1 5 2 3
Output
3133
Note
In the second sample, sequence a consists of 4 elements: {a1, a2, a3, a4} = {1, 3, 2, 5}. Sequence a has exactly 2 longest increasing subsequences of length 3, they are {a1, a2, a4} = {1, 3, 5} and {a1, a3, a4} = {1, 2, 5}.

In the third sample, sequence a consists of 4 elements: {a1, a2, a3, a4} = {1, 5, 2, 3}. Sequence a have exactly 1 longest increasing subsequence of length 3, that is {a1, a3, a4} = {1, 2, 3}.

题意:
n个数,每一个数有三种状态:
(1)不位于任何LIS序列上
(2)位于LIS序列上但是不是所有LIS序列上(LIS序列可能很多,如1 3 2 5,其中2在LIS序列1 2 5上,但是1 3 5也是一个LIS序列)
(3)位于唯一LIS序列上(如1 3 2 5中的5和1)
输出每个数表示的状态
思路:
(1)题目数据开到了1e5,首先求LIS的过程就不能直接n^2转移。有两种nlogn求LIS的方法,一种是 重 新 建 模 \color{red}{重新建模}

  • 原有的dp数组定义是dp[i],i代表a[i]结尾的LIS长度。这样的转移方程是dp[i] = max(dp[j] + 1)(i > j && a[i] > a[j])。
  • 新的定义是dp[i]:长度为i的最长上升子序列元素末尾的最小值。例如 1 3 2 5,1 3 和 1 2都能到达5的状态达到3的长度,但是2比3相对更优。在序列长度相同的前提下, 肯 定 是 \color{red}{肯定是} 结尾数字越小,未来能够匹配的相对更多。该过程可以用二分优化,每次将a[i]更新到能够更新的最后位置。复杂度为nlogn
  • 对于原有模型,麻烦的主要在于那个小于a[i]并且lis值最大的子状态的找寻。学习树状数组写逆序对的时候,为了找寻i > j && a[i] < a[j]的数的个数,我们是将a[i]当做下标,依次更新。同样的,我们需要找寻i > j && a[i] > a[j] && dp[j]最大的j,我们或许也可以通过树状数组求解
  • 我们要满足i > j的条件,直接按顺序for过来就可以了。要满足a[i] > a[j]的条件,类似逆序对的做法,以a[i]/a[j]为下标,下标小于a[i]的所有下标数,都是可选的a[j]。要找寻max{dp[j]},我们则可以将树状数组改为求max的过程,而每一个下标存的是到该位置的最长上升子序列长度。这样寻找子状态过程的复杂度就优化为了nlogn。
    比较好的博客:树状数组求LIS[https://www.cnblogs.com/Rosebud/p/9845935.html]

(2)除了求LIS的过程,题目还需要求是否位于LIS上。但是在每一个位置只能得到以位置结尾的LIS。可行的办法是维护两个dp数组,dp1[i]记录i的LIS,dp2[i]记录n到i的最长下降子序列。只要dp1[i] + dp2[i] = LIS + 1(加1是因为a[i]在两个dp数组中都出现了),就说明i在LIS上。但是即使思路得出,计算dp2[i]也是需要技巧的。

  • 我们需要计算n到i的最长下降子序列 -->计算i到n的最长上升子序列 --> 计算原序列翻转后1到i的最长下降子序列(此时dp状态也翻转了) --> 计算现在这个序列大小关系反转后1到i的最长上升子序列。(可以加个负号,但由于是作为下标,不能成为负数,那么就得用一个很大的数和每个数做差),那么由此方法得出的dp数组为dp[i]:1到i的的最长上升子序列,翻转一下就成了计算n到i的最长下降子序列。

(3)题目还要判断是否在唯一的LIS上。在**(2)**中我们已经能够判断出i是否在LIS上了,还是考虑样例1 3 2 5,很明显1和5在唯一的LIS上,而3和2不在唯一的LIS上,一个明显的特点是dp1[i] + dp2[i] - 1 = LIS的情况中,3和2的dp1都为2,或许这里是突破口。由此考虑状态的定义:LIS = max{dp1[k]} = dp1[i] + dp2[i] - 1;其中一定有k >= i,那么dp[k]一定是由dp[i]转移过来的,假设dp[i]不唯一,转移的过程一定不唯一,那么由i转移得到的LIS也一定不唯一,再由此记录一下所有满足在LIS上的dp1[i]判一下重就可以了。

总结: 写的有点啰嗦了,不过还算是把自己解整道题的学习过程给写出来了。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>using namespace std;
const int maxn = 1e5+7;
int c[maxn];
int a[maxn];
int dp1[maxn],dp2[maxn];
int res[maxn];
map<int,int> mp;
void add(int i,int val)
{while(i < maxn){c[i] = max(c[i],val);i += (i & (-i));}
}int query(int i)
{int ans = 0;while(i){ans = max(ans,c[i]);i -= (i & (-i));}return ans;
}int main()
{int n;scanf("%d",&n);int LIS = 0;for(int i = 1;i <= n;i++){scanf("%d",&a[i]);dp1[i] = 1 + query(a[i] - 1);add(a[i],dp1[i]);LIS = max(LIS,dp1[i]);}reverse(a + 1,a + 1 + n);memset(c,0,sizeof(c));for(int i = 1;i <= n;i++){a[i] = maxn - a[i] + 1;dp2[i] = 1 + query(a[i] - 1);add(a[i],dp2[i]);dp2[i] = query(a[i] - 1) + 1;}reverse(dp2 + 1,dp2 + 1 + n);for(int i = 1;i <= n;i++){if(dp1[i] + dp2[i] - 1 == LIS){mp[dp1[i]]++;}elseres[i] = 1;}for(int i = 1;i <= n;i++){if(dp1[i] + dp2[i] - 1 == LIS){if(mp[dp1[i]] == 1)res[i] = 3;elseres[i] = 2;}printf("%d",res[i]);}return 0;
}

这篇关于(nlogn求LIS,确定状态唯一性)LIS of Sequence CodeForces - 486E的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/907689

相关文章

SpringSecurity JWT基于令牌的无状态认证实现

《SpringSecurityJWT基于令牌的无状态认证实现》SpringSecurity中实现基于JWT的无状态认证是一种常见的做法,本文就来介绍一下SpringSecurityJWT基于令牌的无... 目录引言一、JWT基本原理与结构二、Spring Security JWT依赖配置三、JWT令牌生成与

关于WebSocket协议状态码解析

《关于WebSocket协议状态码解析》:本文主要介绍关于WebSocket协议状态码的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录WebSocket协议状态码解析1. 引言2. WebSocket协议状态码概述3. WebSocket协议状态码详解3

Flutter监听当前页面可见与隐藏状态的代码详解

《Flutter监听当前页面可见与隐藏状态的代码详解》文章介绍了如何在Flutter中使用路由观察者来监听应用进入前台或后台状态以及页面的显示和隐藏,并通过代码示例讲解的非常详细,需要的朋友可以参考下... flutter 可以监听 app 进入前台还是后台状态,也可以监听当http://www.cppcn

MySQL 中的服务器配置和状态详解(MySQL Server Configuration and Status)

《MySQL中的服务器配置和状态详解(MySQLServerConfigurationandStatus)》MySQL服务器配置和状态设置包括服务器选项、系统变量和状态变量三个方面,可以通过... 目录mysql 之服务器配置和状态1 MySQL 架构和性能优化1.1 服务器配置和状态1.1.1 服务器选项

linux进程D状态的解决思路分享

《linux进程D状态的解决思路分享》在Linux系统中,进程在内核模式下等待I/O完成时会进入不间断睡眠状态(D状态),这种状态下,进程无法通过普通方式被杀死,本文通过实验模拟了这种状态,并分析了如... 目录1. 问题描述2. 问题分析3. 实验模拟3.1 使用losetup创建一个卷作为pv的磁盘3.

Java实现状态模式的示例代码

《Java实现状态模式的示例代码》状态模式是一种行为型设计模式,允许对象根据其内部状态改变行为,本文主要介绍了Java实现状态模式的示例代码,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来... 目录一、简介1、定义2、状态模式的结构二、Java实现案例1、电灯开关状态案例2、番茄工作法状态案例

通过prometheus监控Tomcat运行状态的操作流程

《通过prometheus监控Tomcat运行状态的操作流程》文章介绍了如何安装和配置Tomcat,并使用Prometheus和TomcatExporter来监控Tomcat的运行状态,文章详细讲解了... 目录Tomcat安装配置以及prometheus监控Tomcat一. 安装并配置tomcat1、安装

Linux之进程状态&&进程优先级详解

《Linux之进程状态&&进程优先级详解》文章介绍了操作系统中进程的状态,包括运行状态、阻塞状态和挂起状态,并详细解释了Linux下进程的具体状态及其管理,此外,文章还讨论了进程的优先级、查看和修改进... 目录一、操作系统的进程状态1.1运行状态1.2阻塞状态1.3挂起二、linux下具体的状态三、进程的

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

hdu1565(状态压缩)

本人第一道ac的状态压缩dp,这题的数据非常水,很容易过 题意:在n*n的矩阵中选数字使得不存在任意两个数字相邻,求最大值 解题思路: 一、因为在1<<20中有很多状态是无效的,所以第一步是选择有效状态,存到cnt[]数组中 二、dp[i][j]表示到第i行的状态cnt[j]所能得到的最大值,状态转移方程dp[i][j] = max(dp[i][j],dp[i-1][k]) ,其中k满足c