【刷题】BZOJ 3591 最长上升子序列
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 最长上升子序列的更多相关文章
- BZOJ.3591.最长上升子序列(状压DP)
BZOJ 题意:给出\(1\sim n\)的一个排列的一个最长上升子序列,求原排列可能的种类数. \(n\leq 15\). \(n\)很小,参照HDU 4352这道题,我们直接把求\(LIS\)时的 ...
- BZOJ 2423 最长公共子序列
Description 字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列.令给定的字符序列X=“x0,x1,…,xm-1”,序列Y=“y0, ...
- BZOJ 3173 最长上升子序列(树状数组+二分+线段树)
给定一个序列,初始为空.现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数字,我们都想知道此时最长上升子序列长度是多少? 由于序列是顺序插入的,所以当前插入的数字对之 ...
- BZOJ 5427: 最长上升子序列
$f[i] 表示长度为i的最长上升子序列的最后一位的最小值是多少$ 对于普通的$LIS我们可以二分确定位置去更新$ 再来考虑对于这个,如果有某一位没有确定的话 那么这一位是可以随便取的,也就是说,所有 ...
- bzoj 3173 最长上升子序列
Written with StackEdit. Description 给定一个序列,初始为空.现在我们将\(1\)到\(N\)的数字插入到序列中,每次将一个数字插入到一个特定的位置.每插入一个数字, ...
- #leetcode刷题之路32-最长有效括号
给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度. 示例 1:输入: "(()"输出: 2解释: 最长有效括号子串为 "()"示 ...
- #leetcode刷题之路14-最长公共前缀
编写一个函数来查找字符串数组中的最长公共前缀. 如果不存在公共前缀,返回空字符串 "". 示例 1: 输入: ["flower","flow" ...
- #leetcode刷题之路5-最长回文子串
给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 的最大长度为 1000. 示例 1:输入: "babad"输出: "bab"注意: " ...
- 刷题总结:最长公共字串(spoj1811)(后缀自动机)
题目: 就不贴了吧···如题: 题解: 后缀自动机模版题:没啥好说的···· 代码: #include<iostream> #include<cstdio> #include& ...
随机推荐
- css学习杂记
1.css中的&语法 &是sass的语法,代表上一级选择器. 例如: .el-row { margin-bottom: 20px; &:last-child { margin- ...
- Android Bitmap
一 图片表示原理 图片是由每个像素点来组成 像素点就是小方块 图片的大小等于 宽*高*每个像素点的大小 二 加载图片OOM异常 解决办法 其中big.jpg是一张21.2MB的高清图 public c ...
- ESP8266/ESP32模块晶振频偏调试
ESP8266/ESP32模块晶振频偏调试 !> 前提:晶振频偏调试是需要仪器设备的支持才能完成的. 测试环境:IQ2010综合测试仪 本文仅记录有关频偏调试的主要内容,其余不在赘述. IQ20 ...
- Go简单聊天
用Go简单实现网络通信 其余功能可以在这个模型上继续加,比如增加通信人数,实现聊天 server 端 package main import ( "fmt" "log&q ...
- ubuntu下Open vSwitch安装
ubuntu下Open vSwitch安装 有关Open vSwitch的安装,网上有各种的教程资料,但一些已经过时,按照网上的教程,花费了大量时间,都没能安装成功.于是,通过查阅官方安装教程以及综合 ...
- 2019第十届蓝桥杯 E题 迷宫
/*输入 30 50 01010101001011001001010110010110100100001000101010 00001000100000101010010000100000001001 ...
- Ruby知识点二:类
1.追查对象是否属于某个类时,使用is_a?方法 追查某个对象属于哪个类时,使用class方法 判断某个对象是否属于某个类时,使用instance_of?方法 判断类是否包含某个模块,使用inclu ...
- Python基础系列讲解——继承派生和组合的概念剖析
Python作为一门面向对象的语言,它的面向对象体系中主要存在这么两种关系,一个是“类”和“实例”的关系,另一个是“父类”和“子类”的关系. 所谓“类”是从一堆对象中以抽象的方式把相同的特征归类得到的 ...
- 在 Linux 下执行安装 bin 文件
原文: http://www.linuxidc.com/Linux/2014-03/98541.htm
- 团队博客作业week1——成员介绍
我们小组的成员由六人组成,其中包括一名七班的韩国同学. 1.玉钟焕同学 玉钟焕是七班的同学.由于老师为了让我们尽早体验与不熟悉的同学共同工作的环境而提出团队需要跨行政班.于是我们便邀请钟焕同学加入我们 ...