洛谷 P4484 - [BJWC2018]最长上升子序列(状压 dp+打表)
首先看到 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+打表)的更多相关文章
- 【bzoj5161】最长上升子序列 状压dp+打表
题目描述 现在有一个长度为n的随机排列,求它的最长上升子序列长度的期望. 为了避免精度误差,你只需要输出答案模998244353的余数. 输入 输入只包含一个正整数n.N<=28 输出 输出只包 ...
- 洛谷P3959 宝藏(NOIP2017)(状压DP,子集DP)
洛谷题目传送门 Dalao的题解多数是什么模拟退火.DFS剪枝.\(O(3^nn^2)\)的状压DP之类.蒟蒻尝试着把状压改进了一下使复杂度降到\(O(3^nn)\). 考虑到每条边的贡献跟它所在的层 ...
- BZOJ.3591.最长上升子序列(状压DP)
BZOJ 题意:给出\(1\sim n\)的一个排列的一个最长上升子序列,求原排列可能的种类数. \(n\leq 15\). \(n\)很小,参照HDU 4352这道题,我们直接把求\(LIS\)时的 ...
- 洛谷P1896 [SCOI2005]互不侵犯King【状压DP】
题目描述 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. 输入格式: 只有一行,包含两个数N,K ...
- 【洛谷 P1896】[SCOI2005]互不侵犯(状压dp)
题目链接 题意:在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. 这是道状压\(DP\)好题啊.. ...
- BZOJ 2734 洛谷 3226 [HNOI2012]集合选数【状压DP】【思维题】
[题解] 思维题,看了别人的博客才会写. 写出这样的矩阵: 1,3,9,... 2,6,18,... 4,12.36,... 8,24,72,... 我们要做的就是从矩阵中选出一些数字,但是不能选相邻 ...
- 【洛谷5492】[PKUWC2018] 随机算法(状压DP)
点此看题面 大致题意: 用随机算法求一张图的最大独立集:每次随机一个排列,从前到后枚举排列中的点,如果当前点加入点集中依然是独立集,就将当前点加入点集中,最终得到的点集就是最大独立集.求这个随机算法的 ...
- BZOJ 5161: 最长上升子序列 状压dp+查分
好神啊 ~ 打表程序: #include <cstdio> #include <cstring> #include <algorithm> #define N 14 ...
- 洛谷P2396 yyy loves Maths VII【状压dp】
题目:https://www.luogu.org/problemnew/show/P2396 题意:有n个数,每次选择一个表示走$a[i]$步,每个数只能选一次. 最多有两个厄运数字,如果走到了厄运数 ...
随机推荐
- 升级更新 Windows10
升级更新 Windows10:获取 Windows 更新助手 升级 Windows10,它是先下载 Windows10 系统镜像,然后才升级.在下载完 Windows10 后,升级前,有一步骤会询问: ...
- 036—环境变量path
day04 课堂笔记 1.开发第一个java程序:HelloWorld 1.1.程序写完以后,一定要ctrl+s进行保存 源代码若修改,需重新进行编译 1.2.编译阶段 怎么编译?使用什么命令?这个命 ...
- jenkins的安装、配置使用
1.jenkins的使用 (1).需要先下载安装JDK 配置jdk的环境 变量JAVA_HOME的值是 jdk 的安装位置, 然后下载安装tomcat 安装好了之后,打开tomcat下的bin文件夹, ...
- pycharm安装第三方库
https://jingyan.baidu.com/article/4853e1e54b845e1909f7268f.html
- JavaScript之原型与原型链
前言 ❝ JavaScript常被描述为一种「基于原型的语言」--每个对象都拥有一个「原型对象」,对象以其原型为模板.从原型继承属性和放法.原型对象也可能拥有原型,并从中继承属性和方法,一层一层以此类 ...
- leetcode 5/300 最长回文子串 py
目录 题目说明 方法一:动态规划--状态转移方程 方法二:优化中心扩展算法 题目说明 要看明白求得是什么,最长回文字串是指例如cababa中ababa是最长的,不是求回文的部分aba 方法一:动态规划 ...
- maven编码 gbk 的不可映射字符
解决这个问题的思路: 在maven的编译插件中声明正确的字符集编码编码--编译使用的字符集编码与代码文件使用的字符集编码一致!! 安装系统之后,一般中文系统默认字符集是GBK.我们安装的软件一般都继承 ...
- CSP-S 2021 爆零记
前言 本人今年高二蒟蒻OIer,高一刚刚接触OI. 感觉可能要直接退役了555~ 希望还有机会靠NOIP翻盘 Day - 暑假 为了备战CSP提前返校,与xzh一起划水,总之刷了不少题,我也大受震撼 ...
- 结束的NULL
最近同学叫我帮忙看个问题,为啥这个循环没有退出, 代码如下,原本是想拿到最后的NULL指针就可以结束循环 #include <stdio.h> #include <stdlib.h& ...
- 为什么IDEA不推荐你使用@Autowired ?
@Autowired注解相信每个Spring开发者都不陌生了!在DD的Spring Boot基础教程和Spring Cloud基础教程中也都经常会出现. 但是当我们使用IDEA写代码的时候,经常会发现 ...