传送门

参考博文:

  [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. Java多线程5:Synchronized锁机制

    一.前言 在多线程中,有时会出现多个线程对同一个对象的变量进行并发访问的情形,如果不做正确的同步处理,那么产生的后果就是“脏读”,也就是获取到的数据其实是被修改过的. 二.引入Synchronized ...

  2. ES 6 系列 - Promise

    一.含义 是异步编程的一种解决方案,es 6 将其变成了标准. 简单的说是一个容器,里面保存了某个未来才会结束的事件(通常是一个异步操作)的结果.语法上, Promise 是一个对象,从它可以获取异步 ...

  3. zookeeper客户端操作

    ZooKeeper客户端 zkCli.sh 节点的增删改查 在 bin 目录下的  zkCli.sh  就是ZooKeeper客户端 ./zkCli.sh -timeout 5000  -server ...

  4. 给dom对象添加事件

  5. HDU4349-Xiao Ming's Hope-找规律

    打表输出前100之后,找到规律. 不过正确规律是1<<(二进制中1的个数). #include <cstdio> #include <algorithm> usin ...

  6. 杨辉三角(java实现)

    package lizi; import java.util.Scanner; public class Yanghui { private static Scanner input; public ...

  7. 【BZOJ3814】【清华集训2014】简单回路 状压DP

    题目描述 给你一个\(n\times m\)的网格图和\(k\)个障碍,有\(q\)个询问,每次问你有多少个不同的不经过任何一个障碍点且经过\((x,y)\)与\((x+1,y)\)之间的简单回路 \ ...

  8. bzoj 1083: [SCOI2005]繁忙的都市 (最小生成树)

    链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1083 思路:连接所有点,肯定最少是需要n-1条边的,也就是写个最小生成树,记得保存下最大的权 ...

  9. zabbix 监控 WEB 应用性能

    1.介绍使用 zabbix_sender 发送采集的 WEB 状态值,使用 pycurl 来采集 WEB 状态zabbix_sender发送数据,需保证主机名与zabbix server记录的主机名一 ...

  10. luogu3250 网络 (整体二分+树上差分+树状数组)

    首先整体二分,问题变成是否存在经过一个点的满足条件的路径 那么我对于每个路径(a,b,lca),在树状数组的dfn[a]++,dfn[b]++,dfn[lca]--,dfn[fa[lca]--] 然后 ...