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 ...
随机推荐
- Java多线程5:Synchronized锁机制
一.前言 在多线程中,有时会出现多个线程对同一个对象的变量进行并发访问的情形,如果不做正确的同步处理,那么产生的后果就是“脏读”,也就是获取到的数据其实是被修改过的. 二.引入Synchronized ...
- ES 6 系列 - Promise
一.含义 是异步编程的一种解决方案,es 6 将其变成了标准. 简单的说是一个容器,里面保存了某个未来才会结束的事件(通常是一个异步操作)的结果.语法上, Promise 是一个对象,从它可以获取异步 ...
- zookeeper客户端操作
ZooKeeper客户端 zkCli.sh 节点的增删改查 在 bin 目录下的 zkCli.sh 就是ZooKeeper客户端 ./zkCli.sh -timeout 5000 -server ...
- 给dom对象添加事件
- HDU4349-Xiao Ming's Hope-找规律
打表输出前100之后,找到规律. 不过正确规律是1<<(二进制中1的个数). #include <cstdio> #include <algorithm> usin ...
- 杨辉三角(java实现)
package lizi; import java.util.Scanner; public class Yanghui { private static Scanner input; public ...
- 【BZOJ3814】【清华集训2014】简单回路 状压DP
题目描述 给你一个\(n\times m\)的网格图和\(k\)个障碍,有\(q\)个询问,每次问你有多少个不同的不经过任何一个障碍点且经过\((x,y)\)与\((x+1,y)\)之间的简单回路 \ ...
- bzoj 1083: [SCOI2005]繁忙的都市 (最小生成树)
链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1083 思路:连接所有点,肯定最少是需要n-1条边的,也就是写个最小生成树,记得保存下最大的权 ...
- zabbix 监控 WEB 应用性能
1.介绍使用 zabbix_sender 发送采集的 WEB 状态值,使用 pycurl 来采集 WEB 状态zabbix_sender发送数据,需保证主机名与zabbix server记录的主机名一 ...
- luogu3250 网络 (整体二分+树上差分+树状数组)
首先整体二分,问题变成是否存在经过一个点的满足条件的路径 那么我对于每个路径(a,b,lca),在树状数组的dfn[a]++,dfn[b]++,dfn[lca]--,dfn[fa[lca]--] 然后 ...