传送门

参考博文:

  [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)的更多相关文章

  1. 【BZOJ】1076 [SCOI2008]奖励关 期望DP+状压DP

    [题意]n种宝物,k关游戏,每关游戏给出一种宝物,可捡可不捡.每种宝物有一个价值(有负数).每个宝物有前提宝物列表,必须在前面的关卡取得列表宝物才能捡起这个宝物,求期望收益.k<=100,n&l ...

  2. HDU 3920Clear All of Them I(状压DP)

    HDU 3920   Clear All of Them I 题目是说有2n个敌人,现在可以发n枚炮弹,每枚炮弹可以(可以且仅可以)打两个敌人,每一枚炮弹的花费等于它所行进的距离,现在要消灭所有的敌人 ...

  3. CCF 201312-4 有趣的数 (数位DP, 状压DP, 组合数学+暴力枚举, 推公式, 矩阵快速幂)

    问题描述 我们把一个数称为有趣的,当且仅当: 1. 它的数字只包含0, 1, 2, 3,且这四个数字都出现过至少一次. 2. 所有的0都出现在所有的1之前,而所有的2都出现在所有的3之前. 3. 最高 ...

  4. HDU 5067 Harry And Dig Machine(状压dp)

    HDU 5067 Harry And Dig Machine 思路:因为点才10个,在加上一个起点,处理出每一个点之间的曼哈顿距离,然后用状压dp搞,状态表示为: dp[i][s],表示在i位置.走过 ...

  5. HDU - 6125: Free from square (状压DP+分组背包)

    problem:给定N,K.表示你有数1到N,让你最多选择K个数,问有多少种方案,使得选择的数的乘积无平方因子数.N,K<500: solution:显然可以状压DP做,但是500以内的素数还是 ...

  6. HDU 3247 Resource Archiver(AC自动机 + 状压DP + bfs预处理)题解

    题意:目标串n( <= 10)个,病毒串m( < 1000)个,问包含所有目标串无病毒串的最小长度 思路:貌似是个简单的状压DP + AC自动机,但是发现dp[1 << n][ ...

  7. HDU 6984 - Tree Planting(数据分治+状压 dp)

    题面传送门 傻逼卡常屑题/bs/bs,大概现场过得人比较少的原因就是它比较卡常罢(Fog 首先对于这样的题我们很难直接维护,不过注意到这个 \(n=300\) 给得很灵性,\(k\) 比较小和 \(k ...

  8. [转]状态压缩dp(状压dp)

    状态压缩动态规划(简称状压dp)是另一类非常典型的动态规划,通常使用在NP问题的小规模求解中,虽然是指数级别的复杂度,但速度比搜索快,其思想非常值得借鉴. 为了更好的理解状压dp,首先介绍位运算相关的 ...

  9. 状态压缩dp 状压dp 详解

    说到状压dp,一般和二进制少不了关系(还常和博弈论结合起来考,这个坑我挖了还没填qwq),二进制是个好东西啊,所以二进制的各种运算是前置知识,不了解的话走下面链接进百度百科 https://baike ...

随机推荐

  1. 阿里云ECS服务器,CentOS 7.4配置jdk+tomcat+mysql

    参考博客: https://mp.weixin.qq.com/s?__biz=MzIxMzk3Mjg5MQ==&mid=2247484020&idx=1&sn=6e0aa07f ...

  2. Operation not allowed on a unidirectional dataset错误?

    关于网友提出的“ Operation not allowed on a unidirectional dataset错误?”问题疑问,本网通过在网上对“ Operation not allowed o ...

  3. linux寻找依赖文件

    在linux下编译安装软件有时候会遇到依赖文件找不到的情况,很多时候可以通过 sudo apt install -f 来解决:实在找不到怎么办,还有一个绝招可以用: 安装  apt-file sudo ...

  4. tomcat9 点击bin目录下的startup.bat一闪而过

    我装的是tomcat9免安装版,jdk版本是11,之后去tomcat bin目录下点击startup.bat闪退(好吧,只有想办法解决了) 博客中的解决办法五花八门,什么环境变量没配好....不过都不 ...

  5. JarvisOJ Basic easyRSA

    还记得veryeasy RSA吗?是不是不难?那继续来看看这题吧,这题也不难. 已知一段RSA加密的信息为:0xdc2eeeb2782c且已知加密所用的公钥: (N=322831561921859 e ...

  6. Go语言的接口

    一.接口的定义和好处 我们都知道接口给类提供了一种多态的机制,什么是多态,多态就是系统根据类型的具体实现完成不同的行为. 以下代码简单说明了接口的作用 package main import ( &q ...

  7. LVS负载均衡群集

    概述 群集的类型:无论是哪种服务器,都至少包括两台节点服务器,而对外表现为一个整体,只提供一个访问入口(域名或IP地址),相当于一台大型计算机.根据群集所针对的目标差异,可以分为以下三个类型: 1.负 ...

  8. 欧拉筛法模板&&P3383 【模板】线性筛素数

    我们先来看欧拉筛法 •为什么叫欧拉筛呢?这可能是跟欧拉有关 •但是为什么叫线性筛呢?因为它的复杂度是线性的,也就是O(n),我们直接来看代码   #include<cstdio> #inc ...

  9. 一:Newtonsoft.Json 支持序列化与反序列化的.net 对象类型;

    导航目录: Newtonsoft.Json 概述 一:Newtonsoft.Json 支持序列化与反序列化的.net 对象类型:    二:C#对象.集合.DataTable与Json内容互转示例: ...

  10. 【CodeForces 717C】Potions Homework

    BUPT 2017 summer training (for 16) #1G 题意 每个人有一个懒惰值,每个任务有个难度,一开始每个人的任务和懒惰值都为\(a_i\),完成任务时间是懒惰值乘以难度,现 ...