Description

给出1~n的一个排列的一个最长上升子序列,求原排列可能的种类数。

Input

第一行一个整数n。

第二行一个整数k,表示最长上升子序列的长度。

第三行k个整数,表示这个最长上升子序列。

Output

第一行一个整数,表示原排列可能的种类数。

Sample Input

5

3

1 3 4

Sample Output

11

HINT

【样例说明】

11种排列分别为(1, 3, 2, 5, 4), (1, 3, 5, 2, 4), (1, 3, 5, 4, 2), (1, 5, 3, 2, 4), (1, 5, 3, 4, 2), (2, 1, 3, 5, 4), (2, 1, 5, 3, 4), (2, 5, 1, 3, 4), (5, 1, 3, 2, 4), (5, 1, 3, 4, 2), (5, 2, 1, 3, 4)。

【数据规模和约定】

对于30%的数据,1 <= n <= 11。

对于70%的数据,1 <= n <= 14。

对于100%的数据,1 <= n <= 15,答案小于2^31。

Solution

一道dp题

我们先考虑对一个数列求LIS的方法(\(log\) 的那个),一个 \(lis\) 数组,\(lis[i]\) 记录长度为 \(i\) 的LIS的末尾最小可以是多少

对于 \(lis\) 整个数组,不难发现它是单调递增的,所以我们可以用二进制表示它,一样是01表示某个数是否出现在 \(lis\) 数组中,因为递增,所以我们这要知道有哪些数在里面,就可以还原出原来的 \(lis\) 数组

然后考虑本题的dp,我们用一个 \(f\) ,考虑对于当前的LIS,插入新数的情况

所以要保存每个数的三个状态

一是这个数还没有被考虑,二是这个数已被考虑,并且在LIS数组中出现,三是这个数已经被考虑,并且已经被弹出LIS数组

所以用三进制压位,012分别代表上面三个状态

转移时,枚举每一个LIS的情况,然后枚举每一个数,插入进去,再把当前的状态转移到插入后的状态

这种dp题看代码更好理解

#include<bits/stdc++.h>
#define ll long long
#define db double
#define ld long double
const int MAXN=16,MAXN_3=14348907+10;
int A[MAXN],n,m,pos[MAXN],lis[MAXN],vis[MAXN],val[MAXN],f[MAXN_3],ans,qexp3[MAXN];
template<typename T> inline void read(T &x)
{
T data=0,w=1;
char ch=0;
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
x=data*w;
}
template<typename T> inline void write(T x,char c='\0')
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
if(c!='\0')putchar(c);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
int main()
{
read(n);read(m);
for(register int i=1;i<=m;++i)
{
read(A[i]);
A[i]--;
pos[A[i]]=i;
if(i>=2&&A[i-1]>A[i])
{
write(0,'\n');
return 0;
}
}
qexp3[0]=1;
for(register int i=1;i<=n;++i)qexp3[i]=qexp3[i-1]*3;
f[0]=1;
for(register int i=0;i<qexp3[n];++i)
{
if(!f[i])continue;
int x=i,lislen=0,app=0;
for(register int j=0;j<n;++j)
{
val[j]=vis[j]=x%3;
x/=3;
if(vis[j])app++;
if(val[j]==1)lis[lislen++]=j;
}
if(app==n)
{
ans+=f[i];
continue;
}
int ins=0;
for(register int j=0;j<n;++j)
{
if(vis[j])continue;
if(pos[j]>1&&!vis[A[pos[j]-1]])continue;
while(ins<lislen&&lis[ins]<j)ins++;
if(ins==m)continue;
int nxt=i+qexp3[j];
if(ins<lislen)nxt+=qexp3[lis[ins]];
f[nxt]+=f[i];
}
}
write(ans,'\n');
return 0;
}

【刷题】BZOJ 3591 最长上升子序列的更多相关文章

  1. BZOJ.3591.最长上升子序列(状压DP)

    BZOJ 题意:给出\(1\sim n\)的一个排列的一个最长上升子序列,求原排列可能的种类数. \(n\leq 15\). \(n\)很小,参照HDU 4352这道题,我们直接把求\(LIS\)时的 ...

  2. BZOJ 2423 最长公共子序列

    Description 字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列.令给定的字符序列X=“x0,x1,…,xm-1”,序列Y=“y0, ...

  3. BZOJ 3173 最长上升子序列(树状数组+二分+线段树)

    给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数字,我们都想知道此时最长上升子序列长度是多少? 由于序列是顺序插入的,所以当前插入的数字对之 ...

  4. BZOJ 5427: 最长上升子序列

    $f[i] 表示长度为i的最长上升子序列的最后一位的最小值是多少$ 对于普通的$LIS我们可以二分确定位置去更新$ 再来考虑对于这个,如果有某一位没有确定的话 那么这一位是可以随便取的,也就是说,所有 ...

  5. bzoj 3173 最长上升子序列

    Written with StackEdit. Description 给定一个序列,初始为空.现在我们将\(1\)到\(N\)的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数字, ...

  6. #leetcode刷题之路32-最长有效括号

    给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度. 示例 1:输入: "(()"输出: 2解释: 最长有效括号子串为 "()"示 ...

  7. #leetcode刷题之路14-最长公共前缀

    编写一个函数来查找字符串数组中的最长公共前缀. 如果不存在公共前缀,返回空字符串 "". 示例 1: 输入: ["flower","flow" ...

  8. #leetcode刷题之路5-最长回文子串

    给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 的最大长度为 1000. 示例 1:输入: "babad"输出: "bab"注意: " ...

  9. 刷题总结:最长公共字串(spoj1811)(后缀自动机)

    题目: 就不贴了吧···如题: 题解: 后缀自动机模版题:没啥好说的···· 代码: #include<iostream> #include<cstdio> #include& ...

随机推荐

  1. java学习(三)类、实例

    类 public class Dog{ String breed; int age; String color; void barking(){ } void hungry(){ } void sle ...

  2. WebGL——osg框架学习一

    从今天开始,我们开始正式的学习osg框架,今天我们学习的是osg的渲染模块,我们来看一下代码结构. 所有DrawXXX的js模块都是渲染的模块,我们逐一来简单介绍一下,第一个Drawable.js,这 ...

  3. Window10家庭版启动hyper-v虚拟机组件

    在安装docker的时候发现如果直接使用docker for windows,对系统的要求是window10专业版或企业版,家庭版本身没有hyper-v,不能支持 虚拟化.但是后来我在搜索过程中发现, ...

  4. MAVEN项目导入src/test/java项目报错

    转载博客:https://blog.csdn.net/gengjianchun/article/details/78679036    https://blog.csdn.net/jsloveyou/ ...

  5. 4星|《钱的历史》:大英博物馆的钱币简史,彩图众多不适合在kindle上阅读

    钱的历史(大英博物馆权威出品,一部金钱简史) 大英博物馆的两位钱币馆馆长的作品.非常专业.基本是世界钱币简史.从钱币的发展变迁讲到涉及到的历史大事,重心当然是欧洲的钱币史,中国.印度也各安排了一章. ...

  6. C#中字符串 "驻留"与Lock(转载)

    class TestWorker 2 {         3     public void DoMultiThreadedWork(object someParameter) 4     { 5   ...

  7. 如何解决zabbix snmp异常超时、不稳定、时通时断:Timeout

    针对平时工作中,zabbix snmp出现异常超时.不稳定.时通时断:Timeout while connecting 等的情况,以下我将以使用乐维监控为例,进行解决方案的详细叙述.   一.问题:设 ...

  8. centos7.6 安装配置rabbitmq

    IP地址:192.168.200.108 安装erlang 和 依赖环境 yum install -y socat yum install -y erlang 安装rabbitmq yum insta ...

  9. NO.6:自学python之路------面向对象、内存持久化

    引言 虽然加速学习了,可是还是感觉进度不够快,担心.还得准备毕业论文,真是焦虑. 正文 面向对象 编程是程序员用特定语法+数据结构+算法组成的代码,告诉计算机如何执行任务的过程.对不同的编程方式的特点 ...

  10. 2、Ansible在使用过程中出现的错误解决方法

    1.安装完成后允许命令出错 Traceback (most recent call last): File "/usr/bin/ansible", line 197, in (ru ...