洛谷题面传送门

首先看到 LIS 我们可以想到它的 \(\infty\) 种求法(bushi),但是对于此题而言,既然题目出这样一个数据范围,硬要暴搜过去也不太现实,因此我们需想到用某种奇奇怪怪的方式进行状态压缩 DP,这样一来就可以排除掉不少常用的求 DP 的方法:譬如最常用的从左往右顺着钦定元素并设 \(f_i\) 表示以 \(i\) 结尾的 LIS 的长度的方法,因此考虑换个角度,从小到大添加元素。还是设 \(f_i\) 表示以 \(i\) 结尾的 LIS 的长度,那么考虑在一轮中,我们在 \(i\) 和 \(i+1\) 这两个位置中间插入一个比当前所有数都大的数会对 \(f\) 产生怎样的影响,有:

  • \(f_{i+1}=1+\max\limits_{j=1}^if_j\)
  • 对于 \(j>i\),有新的 \(f_{j+1}\) 等于 \(f_j\)。

注意到这里涉及前缀 \(\max\),因此设 \(mf_i=\max\limits_{j=1}^if_j\),又注意到相邻两个 \(mf_i\) 的差最多为 \(1\),因此考虑 \(mf_i\) 的差分序列 \(d_i=mf_i-mf_{i-1}\),根据之前的推论显然它是一个 \(01\) 序列,这样就天然地形成了状压 \(dp\) 的模型。由于我们的 \(dp\) 都建立在差分序列的基础上,因此我们再来探究下加入一个比当前所有数都大的数会对差分序列产生怎样的影响:

  • \(d_{i+1}=1\)
  • 对于所有 \(j\ge i+1\),有新的 \(d_{j+1}\) 等于原来的 \(d_j\)。
  • 进行以上两个操作之后,我们找到 \(i+1\) 后面第一个 \(d_j=1\) 的 \(j\)——如果不存在这样的 \(j\) 则跳过这一步,并令 \(d_j=0\)。

这样我们就可以设 \(dp_{i,j}\) 表示当前插入了 \(1\sim i\),\(d\) 的状态为 \(j\) 的方案数,转移就枚举在哪里插入 \(i+1\),然后二进制模拟 \(d\) 的变化即可。注意到 \(j\) 只用枚举到 \(2^i\),因此 \((i,j)\) 的总枚举量是 \(2^n\) 的,再加上转移的 \(n\),总复杂度 \(2^n·n\),注意滚动数组优化空间,否则会获得 MLE 0 的好成绩。

void add(int &x,int v){((x+=v)>=MOD)&&(x-=MOD);}
int qpow(int x,int e){
int ret=1;
for(;e;e>>=1,x=1ll*x*x%MOD) if(e&1) ret=1ll*ret*x%MOD;
return ret;
}
int n,dp[2][134217733];
int main(){
scanf("%d",&n);
dp[1][1>>1]=1;int nxt=0,cur=1;
for(int i=1;i<n;i++){
for(int j=0;j<(1<<i+1);j++) dp[nxt][j>>1]=0;
for(int j=1;j<(1<<i);j+=2) if(dp[cur][j>>1]){
// printf("%d %d %d\n",i,j,dp[cur][j]);
for(int k=0;k<=i;k++){
int nmsk=0;
if(k) nmsk=j&((1<<k)-1);
nmsk|=(1<<k);
int rst=((1<<i)-1)^((!k)?0:((1<<k)-1));
nmsk|=(j&rst)<<1;
if((j&rst)){int S=j&rst;nmsk^=(S&(-S))<<1;}
add(dp[nxt][nmsk>>1],dp[cur][j>>1]);
}
} swap(cur,nxt);
} int res=0,fac=1;
for(int i=1;i<(1<<n);i+=2) res=(res+1ll*__builtin_popcount(i)*dp[cur][i>>1])%MOD;
for(int i=1;i<=n;i++) fac=1ll*fac*i%MOD;
res=1ll*res*qpow(fac,MOD-2)%MOD;
printf("%d\n",res);
return 0;
}

直接按照上面的做法写大约会 TLE 3~6 个点,取决于你的实现,不过注意到这题长得一脸打表的样子,于是你对 \(n\) 比较大的情况在本地跑一下上面的代码,算出答案特判下即可通过此题。

并没有看懂楼下 EI 神仙的题解

void add(int &x,int v){((x+=v)>=MOD)&&(x-=MOD);}
int qpow(int x,int e){
int ret=1;
for(;e;e>>=1,x=1ll*x*x%MOD) if(e&1) ret=1ll*ret*x%MOD;
return ret;
}
int n,dp[2][134217733];
int main(){
scanf("%d",&n);
if(n==22) return puts("749077581"),0;
if(n==23) return puts("301075008"),0;
if(n==24) return puts("314644758"),0;
if(n==25) return puts("102117126"),0;
if(n==26) return puts("819818153"),0;
if(n==27) return puts("273498600"),0;
if(n==28) return puts("267588741"),0;
dp[1][1>>1]=1;int nxt=0,cur=1;
for(int i=1;i<n;i++){
for(int j=0;j<(1<<i+1);j++) dp[nxt][j>>1]=0;
for(int j=1;j<(1<<i);j+=2) if(dp[cur][j>>1]){
// printf("%d %d %d\n",i,j,dp[cur][j]);
for(int k=0;k<=i;k++){
int nmsk=0;
if(k) nmsk=j&((1<<k)-1);
nmsk|=(1<<k);
int rst=((1<<i)-1)^((!k)?0:((1<<k)-1));
nmsk|=(j&rst)<<1;
if((j&rst)){int S=j&rst;nmsk^=(S&(-S))<<1;}
add(dp[nxt][nmsk>>1],dp[cur][j>>1]);
}
} swap(cur,nxt);
} int res=0,fac=1;
for(int i=1;i<(1<<n);i+=2) res=(res+1ll*__builtin_popcount(i)*dp[cur][i>>1])%MOD;
for(int i=1;i<=n;i++) fac=1ll*fac*i%MOD;
res=1ll*res*qpow(fac,MOD-2)%MOD;
printf("%d\n",res);
return 0;
}

洛谷 P4484 - [BJWC2018]最长上升子序列(状压 dp+打表)的更多相关文章

  1. 【bzoj5161】最长上升子序列 状压dp+打表

    题目描述 现在有一个长度为n的随机排列,求它的最长上升子序列长度的期望. 为了避免精度误差,你只需要输出答案模998244353的余数. 输入 输入只包含一个正整数n.N<=28 输出 输出只包 ...

  2. 洛谷P3959 宝藏(NOIP2017)(状压DP,子集DP)

    洛谷题目传送门 Dalao的题解多数是什么模拟退火.DFS剪枝.\(O(3^nn^2)\)的状压DP之类.蒟蒻尝试着把状压改进了一下使复杂度降到\(O(3^nn)\). 考虑到每条边的贡献跟它所在的层 ...

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

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

  4. 洛谷P1896 [SCOI2005]互不侵犯King【状压DP】

    题目描述 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. 输入格式: 只有一行,包含两个数N,K ...

  5. 【洛谷 P1896】[SCOI2005]互不侵犯(状压dp)

    题目链接 题意:在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. 这是道状压\(DP\)好题啊.. ...

  6. BZOJ 2734 洛谷 3226 [HNOI2012]集合选数【状压DP】【思维题】

    [题解] 思维题,看了别人的博客才会写. 写出这样的矩阵: 1,3,9,... 2,6,18,... 4,12.36,... 8,24,72,... 我们要做的就是从矩阵中选出一些数字,但是不能选相邻 ...

  7. 【洛谷5492】[PKUWC2018] 随机算法(状压DP)

    点此看题面 大致题意: 用随机算法求一张图的最大独立集:每次随机一个排列,从前到后枚举排列中的点,如果当前点加入点集中依然是独立集,就将当前点加入点集中,最终得到的点集就是最大独立集.求这个随机算法的 ...

  8. BZOJ 5161: 最长上升子序列 状压dp+查分

    好神啊 ~ 打表程序: #include <cstdio> #include <cstring> #include <algorithm> #define N 14 ...

  9. 洛谷P2396 yyy loves Maths VII【状压dp】

    题目:https://www.luogu.org/problemnew/show/P2396 题意:有n个数,每次选择一个表示走$a[i]$步,每个数只能选一次. 最多有两个厄运数字,如果走到了厄运数 ...

随机推荐

  1. 12. 亿级流量电商系统JVM模型参数二次优化

    亿级流量电商系统JVM模型参数预估方案,在原来的基础上采用ParNew+CMS垃圾收集器 一.亿级流量分析及jvm参数设置 1. 需求分析 大促在即,拥有亿级流量的电商平台开发了一个订单系统,我们应该 ...

  2. 【数据结构 C++】排序——冒泡、插入、选择、希尔、归并、快排、堆排序

    LeetCode 912. 排序数组 给你一个整数数组 nums,请你将该数组升序排列. 示例 1: 输入:nums = [5,2,3,1] 输出:[1,2,3,5] 示例 2: 输入:nums = ...

  3. 性能利器 Takin 来了!首个生产环境全链路压测平台正式开源

    6 月 25 日,国内知名的系统高可用专家数列科技宣布开源旗下核心产品能力,对外开放生产全链路压测平台产品的源代码,并正式命名为 Takin. 目前中国人寿.顺丰科技.希音.中通快递.中国移动.永辉超 ...

  4. Coursera Deep Learning笔记 改善深层神经网络:优化算法

    笔记:Andrew Ng's Deeping Learning视频 摘抄:https://xienaoban.github.io/posts/58457.html 本章介绍了优化算法,让神经网络运行的 ...

  5. python标准库glob 递归目录下所有文件

    import glob for i in glob.glob(r'C:\Desktop\**',recursive=True): print(i) """ re:?*[0 ...

  6. 通过Nacos动态刷新Spring Cloud Gateway的路由

    通过Nacos动态刷新Spring Cloud Gateway的路由 一.背景 二.解决方案 三.实现功能 四.实现步骤 1.网关服务的实现 1.pom文件 2.bootstrap.yml配置文件 3 ...

  7. CanalAdmin搭建Canal Server集群

    CanalAdmin搭建Canal Server集群 一.背景 二.机器情况 三.实现步骤 1.下载canal admin 2.配置canalAdmin 3.初始化canal admin数据库 4.启 ...

  8. android tcp通讯

    Andoird TCP通讯 前言 最近在写一个即时通讯的项目,有一些心得,写出来给大家分享指正一下. 简单描述一下这个项目: 实时查询车辆运行状态的项目,走TCP通迅. 接口采用GZIP压缩. 后台是 ...

  9. 从零开始的DIY智能家居 - 基于 ESP32 的智能水浊度传感器

    前言 家里有个鱼缸养了几条鱼来玩玩,但是换水的问题着实头疼,经常一个不注意就忘记换水,鱼儿就没了.o(╥﹏╥)o 在获得 Spirit 1 边缘计算机 后就相当于有了一个人智能设备服务器,可以自己开发 ...

  10. hdu 3635 Dragon Balls(并查集)

    题意: N个城市,每个城市有一个龙珠. 两个操作: 1.T A B:A城市的所有龙珠转移到B城市. 2.Q A:输出第A颗龙珠所在的城市,这个城市里所有的龙珠个数,第A颗龙珠总共到目前为止被转移了多少 ...