hdu 4352 "XHXJ's LIS"(数位DP+状压DP+LIS)
参考博文:
[1]:http://www.voidcn.com/article/p-ehojgauy-ot.html
题解:
将数字num字符串化;
求[L,R]区间最长上升子序列长度为 K 的总个数;
题解:
也不算是题解,只是谈谈我对此题解法的理解;
学到数位DP的话,应该已经学过状压DP 和 LIS O( nlog(n) )解法吧(默认学过了);
对于此题,一共就10个不同的数字 "0~9",对于长度为 K 的最长上升子序列,如果不适用记忆化搜索的话,一定会重复计算好多好多次;
例如,如果 K = 10,那么,最长上升子序列一定顺序包含 0 1 2 3 4 5 6 7 8 9 这十个数字,而最多可以达到19位;
那么,除这十位外,还有 9 位可以由 0~9 的任意数字随机排列组成,那么重复计算的次数是非常多的。
关键就是如何记录已经求过的状态?
首先介绍一下此题如何使用状压;
正如上例,我们只需关注 0~9 这十个数字是否出现过,以及是否按顺序出现,而不必关心其他位数是由什么组成的,
那么,这就要用到状压DP的思想了;
对于 0~9 这十位数:
9 8 7 6 5 4 3 2 1 0
_ _ _ _ _ _ _ _ _ _
每个数字下的横杠可填 0 或 1 这两个数;
0:不含当前数字;
1:含有当前数字;
那么,对于状态 state ,判断其是否含有数字 i ,只需判断 state&(1<<i) 是否为 1 即可;
首先是预处理:
定义 lis[ i ] : 状态 i 的最长上升子序列的长度
for(int i=;i < <<;++i)
{
lis[i]=;
for(int j=;j < ;++j)
lis[i] += (i&(<<j)) ? :;
}
接下来,看看这个代码的作用:
int LIS(int state,int num)
{
for(int i=num;i < ;++i)
if(state&(<<i))
return (state^(<<i))|(<<num);
return state|(<<num);
}
笼统的解释一下就是:插入 num 后,将 state 中的第一个大于等于 num 位的 1 变为 0,并将 num 位 置为 1;
例如,假设 state = (1,000,110,001)(2);
可得,当前 state 已经形成了由 0,4,5,9 构成的长度为 4 的最长上升子序列;
如果当前加入的数字为 3 ,根据 LIS 的思想,在之前形成的最长上升子序列中找到第一个大于等于 3 的数,
并将3和其互换,那么返回的值就是 (1,000,101,001)(2);
那么,这段代码到底是干啥用的呢?
定义dp[ curPos ][ state ][ K ] : 来到curPos 位置时,状态为 state 所形成的最长上升子序列长度为 K 的总个数;
核心代码:
ll DFS(int curPos,int state,bool lead,bool limit)
{
if(curPos == -)
return lis[state] == K ? :;
if(!limit&&dp[curPos][state][K] != -)
return dp[curPos][state][K]; int up=limit ? digit[curPos]:;
ll ans=;
for(int i=;i <= up;++i)
ans += DFS(curPos-,lead&&i== ? :LIS(state,i),lead&&i==,limit&&i==digit[curPos]); if(!limit)
dp[curPos][state][K]=ans; return ans;
}
1~9行不再赘述;
主要看一下第11行的作用;
第二个参数赋的值为 lead&&i==0 ? 0:LIS(state,i) ,给下一个状态赋 0 很好理解,关键是 LIS(state,i);
这就对应着上述对 LIS() 的解释;
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a)) ll N,M;
int K;
int digit[];
ll dp[][<<][];
int lis[<<]; int LIS(int state,int num)
{
for(int i=num;i < ;++i)
if(state&(<<i))
return (state^(<<i))|(<<num);
return state|(<<num);
}
ll DFS(int curPos,int state,bool lead,bool limit)
{
if(curPos == -)
return lis[state] == K ? :;
if(!limit&&dp[curPos][state][K] != -)
return dp[curPos][state][K]; int up=limit ? digit[curPos]:;
ll ans=;
for(int i=;i <= up;++i)
ans += DFS(curPos-,lead&&i== ? :LIS(state,i),lead&&i==,limit&&i==digit[curPos]); if(!limit)
dp[curPos][state][K]=ans; return ans;
}
ll Solve(ll x)
{
int k=;
while(x)
{
digit[k++]=x%;
x /= ;
}
return DFS(k-,,true,true);
}
int main()
{
int test;
scanf("%d",&test);
mem(dp,-); for(int i=;i < <<;++i)
{
lis[i]=;
for(int j=;j < ;++j)
lis[i] += (i&(<<j)) ? :;
}
for(int kase=;kase <= test;++kase)
{
scanf("%lld%lld%d",&N,&M,&K);
printf("Case #%d: %lld\n",kase,Solve(M)-Solve(N-));
}
return ;
}
当然,也可提前预处理出状态 i 插入数字 j 后形成的状态,这就对应着参考博文中的 nex[][] 数组;
hdu 4352 "XHXJ's LIS"(数位DP+状压DP+LIS)的更多相关文章
- 【BZOJ】1076 [SCOI2008]奖励关 期望DP+状压DP
[题意]n种宝物,k关游戏,每关游戏给出一种宝物,可捡可不捡.每种宝物有一个价值(有负数).每个宝物有前提宝物列表,必须在前面的关卡取得列表宝物才能捡起这个宝物,求期望收益.k<=100,n&l ...
- HDU 3920Clear All of Them I(状压DP)
HDU 3920 Clear All of Them I 题目是说有2n个敌人,现在可以发n枚炮弹,每枚炮弹可以(可以且仅可以)打两个敌人,每一枚炮弹的花费等于它所行进的距离,现在要消灭所有的敌人 ...
- CCF 201312-4 有趣的数 (数位DP, 状压DP, 组合数学+暴力枚举, 推公式, 矩阵快速幂)
问题描述 我们把一个数称为有趣的,当且仅当: 1. 它的数字只包含0, 1, 2, 3,且这四个数字都出现过至少一次. 2. 所有的0都出现在所有的1之前,而所有的2都出现在所有的3之前. 3. 最高 ...
- HDU 5067 Harry And Dig Machine(状压dp)
HDU 5067 Harry And Dig Machine 思路:因为点才10个,在加上一个起点,处理出每一个点之间的曼哈顿距离,然后用状压dp搞,状态表示为: dp[i][s],表示在i位置.走过 ...
- HDU - 6125: Free from square (状压DP+分组背包)
problem:给定N,K.表示你有数1到N,让你最多选择K个数,问有多少种方案,使得选择的数的乘积无平方因子数.N,K<500: solution:显然可以状压DP做,但是500以内的素数还是 ...
- HDU 3247 Resource Archiver(AC自动机 + 状压DP + bfs预处理)题解
题意:目标串n( <= 10)个,病毒串m( < 1000)个,问包含所有目标串无病毒串的最小长度 思路:貌似是个简单的状压DP + AC自动机,但是发现dp[1 << n][ ...
- HDU 6984 - Tree Planting(数据分治+状压 dp)
题面传送门 傻逼卡常屑题/bs/bs,大概现场过得人比较少的原因就是它比较卡常罢(Fog 首先对于这样的题我们很难直接维护,不过注意到这个 \(n=300\) 给得很灵性,\(k\) 比较小和 \(k ...
- [转]状态压缩dp(状压dp)
状态压缩动态规划(简称状压dp)是另一类非常典型的动态规划,通常使用在NP问题的小规模求解中,虽然是指数级别的复杂度,但速度比搜索快,其思想非常值得借鉴. 为了更好的理解状压dp,首先介绍位运算相关的 ...
- 状态压缩dp 状压dp 详解
说到状压dp,一般和二进制少不了关系(还常和博弈论结合起来考,这个坑我挖了还没填qwq),二进制是个好东西啊,所以二进制的各种运算是前置知识,不了解的话走下面链接进百度百科 https://baike ...
随机推荐
- 阿里云ECS服务器,CentOS 7.4配置jdk+tomcat+mysql
参考博客: https://mp.weixin.qq.com/s?__biz=MzIxMzk3Mjg5MQ==&mid=2247484020&idx=1&sn=6e0aa07f ...
- Operation not allowed on a unidirectional dataset错误?
关于网友提出的“ Operation not allowed on a unidirectional dataset错误?”问题疑问,本网通过在网上对“ Operation not allowed o ...
- linux寻找依赖文件
在linux下编译安装软件有时候会遇到依赖文件找不到的情况,很多时候可以通过 sudo apt install -f 来解决:实在找不到怎么办,还有一个绝招可以用: 安装 apt-file sudo ...
- tomcat9 点击bin目录下的startup.bat一闪而过
我装的是tomcat9免安装版,jdk版本是11,之后去tomcat bin目录下点击startup.bat闪退(好吧,只有想办法解决了) 博客中的解决办法五花八门,什么环境变量没配好....不过都不 ...
- JarvisOJ Basic easyRSA
还记得veryeasy RSA吗?是不是不难?那继续来看看这题吧,这题也不难. 已知一段RSA加密的信息为:0xdc2eeeb2782c且已知加密所用的公钥: (N=322831561921859 e ...
- Go语言的接口
一.接口的定义和好处 我们都知道接口给类提供了一种多态的机制,什么是多态,多态就是系统根据类型的具体实现完成不同的行为. 以下代码简单说明了接口的作用 package main import ( &q ...
- LVS负载均衡群集
概述 群集的类型:无论是哪种服务器,都至少包括两台节点服务器,而对外表现为一个整体,只提供一个访问入口(域名或IP地址),相当于一台大型计算机.根据群集所针对的目标差异,可以分为以下三个类型: 1.负 ...
- 欧拉筛法模板&&P3383 【模板】线性筛素数
我们先来看欧拉筛法 •为什么叫欧拉筛呢?这可能是跟欧拉有关 •但是为什么叫线性筛呢?因为它的复杂度是线性的,也就是O(n),我们直接来看代码 #include<cstdio> #inc ...
- 一:Newtonsoft.Json 支持序列化与反序列化的.net 对象类型;
导航目录: Newtonsoft.Json 概述 一:Newtonsoft.Json 支持序列化与反序列化的.net 对象类型: 二:C#对象.集合.DataTable与Json内容互转示例: ...
- 【CodeForces 717C】Potions Homework
BUPT 2017 summer training (for 16) #1G 题意 每个人有一个懒惰值,每个任务有个难度,一开始每个人的任务和懒惰值都为\(a_i\),完成任务时间是懒惰值乘以难度,现 ...