洛谷题面传送门

首先看到 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. the Agiles Scrum Meeting 6

    会议时间:2020.4.14 20:00 1.每个人的工作 今天已完成的工作 增量组:开发广播正文展开收起功能 issues:增量组:广播正文展开收起功能实现 完善组:修复冲刺部分的bug issue ...

  2. 请问为什么要用三极管驱动mos,直接用mos有什么缺点呢?

    可能无法完全导通,电流可能过小使导通所需时间变长,最终导致发热严重       回复 举报     csaaa DIY七级 3# 发表于 2016-7-12 14:11:59 直接驱动mos也没什么问 ...

  3. 常用Java API:Calendar日期类

    摘要 在蓝桥杯中有关于日期计算的问题,正好java中的Date类和Calendar类提供了对日期处理的一些方法.Date类大部分方法已经废弃了,所以本文将详细介绍Calendar类. Calendar ...

  4. 万能构造解决Rolle中值问题

    只要原函数是两个函数的乘积形式,皆可此构造.

  5. 转帖:新版vivado2019.2新增增量综合功能

    从 Vivado 2019.1 版本开始,Vivado 综合引擎就已经可以支持增量流程了.这使用户能够在设计变化较小时减少总的综合运行时间. Vivado IDE 和 Tcl 命令批处理模式都可以启用 ...

  6. Luogu P1654 OSU! | 期望

    题目链接 很妙的一道题. 题目要求$X^3$的期望值. 直接求不好求. 考虑先求出$X$和$X^2$的期望值,然后再求$X^3$的期望值. 迎.刃.而.解. #include<iostream& ...

  7. hdu 1501 Zipper(DP)

    题意: 给三个字符串str1.str2.str3 问str1和str2能否拼接成str3.(拼接的意思可以互相穿插) 能输出YES否则输出NO. 思路: 如果str3是由str1和str2拼接而成,s ...

  8. 重新整理 .net core 实践篇——— filter[四十四]

    前言 简单介绍一下filter 正文 filter 的种类,微软文档中写道: 每种筛选器类型都在筛选器管道中的不同阶段执行: 授权筛选器最先运行,用于确定是否已针对请求为用户授权. 如果请求未获授权, ...

  9. Docker 部署前后端项目

    Docker 部署前后端项目 平生不会相思,才会相思,便害相思. 简介:都是被逼的,从零开始一个Docker 部署九个微服务和三个前端项目.其中,这些服务需要用到Nacos.MySQL.Nginx.E ...

  10. Python使用ConfigParser模块读取配置文件(config.ini)以及写入配置文件

    前言 使用配置文件来灵活的配置一些参数是一件很常见的事情,配置文件的解析并不复杂,在python里更是如此,在官方发布的库中就包含有做这件事情的库,那就是configParser.configPars ...