HDU4352 XHXJ's LIS 题解 数位DP
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4352
题目大意:
求区间 \([L,R]\) 范围内最长上升子序列(Longest increasing subsequence,简称LIS)长度为 \(k\) 的数的数量。
举个例子:
\(123\) 的LIS只有一个\(123\),所以它的LIS的长度是 \(3\);
\(101\) 的LIS只有一个\(01\),所以它的LIS的长度是 \(2\);
\(132\) 的LIS有\(13\)和\(12\),所以它的LIS的长度是 \(2\)。
现在每次给你三个数 \(L,R,k\) ,你要求区间 \([L,R]\) 范围内LIS长度为 \(k\) 的数有多少个。
解题思路:
本题使用 数位DP 进行求解。
但是我觉得比较必要的先决条件是:你要对如何 使用二分的方法求解LIS 有一个比较深刻的理解!
虽然这并不是必须的,但是这能够帮助你理解状态转移的过程。
设状态 \(dp[pos][sta][k]\) 表示对于当前的这个 \(k\):
- 当前所处的数位为 \(pos\),
- 当前LIS的状态为 \(sta\)
时的数量。
\(sta\) 涉及状态压缩的思想,他表示当前LIS中的元素由哪些组成。
一开始初始时候的 \(sta\) 为 \(0000000000\)(10个\(0\))。
在某一阶段,
如果当前已经选择了 \(a[0]\), \(a[1]\) 和 \(a[3]\) ,那么当前的状态就是 \(0000001011\);
如果当前已经选择了 \(a[2]\), \(a[4]\) 和 \(a[7]\) ,那么当前的状态就是 \(0010010100\)。
接下来我们来举例一个数 \(15234\) 来演示我们数位DP的过程:
初始时 \(sta\) 为 \(0000000000\);
加入 \(1\) ,此时状态变成 \(0000000010\);
加入 \(5\) ,此时状态变成 \(0000100010\);
加入 \(2\) ,此时状态变成 \(0000000110\),
注意:这里是最重要的地方!!
为什么加入 \(2\) 之后 \(5\) 对应的位置会变成 \(0\) 呢?
因为我们这里记录的状态就是我们二分LIS对应的状态,
刚加入 \(5\) 的时候,状态是 \(0000100010\) ,它表示新加入的元素要构成一个长度为 \(2\) 的LIS,必须比 \(1\) 大,
新加入的元素要构成一个长度为 \(3\) 的LIS,必须比 \(5\) 大。
而加入 \(2\) 之后,情况就大大改观了,因为此时要构成一个长度为 \(2\) 的LIS,只需要比 \(2\) 大就可以了。
所以对于当前状态 \(sta\) 和当前数位要放的数字 \(i\) ,
如果 \(sta\) 的第 \(i\) 位为 \(1\) ,那么新的状态仍旧是 \(sta\)(因为LIS中存在 \(i\));
如果 \(sta\) 的第 \(i\) 为为 \(0\) ,那么:
- 如果 \(sta\) (没有特别强调都是指二进制)中没有任何比 \(i\) 大的位上为 \(1\) ,则新状态就是
sta | (1<<i)
; - 否则,将比 \(i\) 大的最小的那位置为 \(0\),再将第 \(i\) 位置为 \(1\),就是新的状态。
实现代码如下:
#include <bits/stdc++.h>
using namespace std;
long long f[22][1030][10];
int n, k, a[22];
void init() {
memset(f, -1, sizeof(f));
}
int new_sta(int pos, int sta, int i) {
if (!sta && i==0 && pos>0) return 0;
if (!(sta>>(i+1)) || (sta&(1<<i))) return sta | (1<<i);
for (int k = k = i+1; k < 10; k ++) if (sta & (1<<k)) return (sta ^ (1<<k)) | (1<<i);
}
long long dfs(int pos, int sta, bool limit) {
if (pos < 0) return __builtin_popcount(sta) == k ? 1 : 0;
if (!limit && f[pos][sta][k] != -1) return f[pos][sta][k];
int up = limit ? a[pos] : 9;
long long tmp = 0;
for (int i = 0; i <= up; i ++) {
tmp += dfs(pos-1, new_sta(pos, sta, i), limit && i==up);
}
if (!limit) f[pos][sta][k] = tmp;
return tmp;
}
long long get_num(long long x) {
int pos = 0;
while (x) {
a[pos++] = x % 10;
x /= 10;
}
return dfs(pos-1, 0, true);
}
int T;
long long L, R;
int main() {
init();
scanf("%d", &T);
for (int cas = 1; cas <= T; cas ++) {
scanf("%lld%lld%d", &L, &R, &k);
printf("Case #%d: %lld\n", cas, get_num(R) - get_num(L-1));
}
return 0;
}
HDU4352 XHXJ's LIS 题解 数位DP的更多相关文章
- hdu4352 XHXJ's LIS(数位dp)
题目传送门 XHXJ's LIS Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- 【HDU 4352】 XHXJ's LIS (数位DP+状态压缩+LIS)
XHXJ's LIS Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- hdu 4352 "XHXJ's LIS"(数位DP+状压DP+LIS)
传送门 参考博文: [1]:http://www.voidcn.com/article/p-ehojgauy-ot.html 题解: 将数字num字符串化: 求[L,R]区间最长上升子序列长度为 K ...
- 【HDU】4352 XHXJ's LIS(数位dp+状压)
题目 传送门:QWQ 分析 数位dp 状压一下现在的$ O(nlogn) $的$ LIS $的二分数组 数据小,所以更新时直接暴力不用二分了. 代码 #include <bits/stdc++. ...
- HDU - 4352 - XHXJ's LIS(数位DP)
链接: https://vjudge.net/problem/HDU-4352 题意: a 到 b中一个数组成递增子序列长度等于k的数的个数 思路: 因为只有10个数,使用二进制维护一个递增序列,每次 ...
- hdu 4352 XHXJ's LIS (数位dp+状态压缩)
Description #define xhxj (Xin Hang senior sister(学姐)) If you do not know xhxj, then carefully readin ...
- HDU 4352 XHXJ's LIS (数位DP,状压)
题意: 前面3/4的英文都是废话.将一个正整数看成字符串,给定一个k,问区间[L,R]中严格的LIS=k的数有多少个? 思路: 实在没有想到字符0~9最多才10种,况且也符合O(nlogn)求LIS的 ...
- hdu4352 XHXJ's LIS(数位DP + LIS + 状态压缩)
#define xhxj (Xin Hang senior sister(学姐)) If you do not know xhxj, then carefully reading the entire ...
- hdu4352 XHXJ's LIS[数位DP套状压DP+LIS$O(nlogn)$]
统计$[L,R]$内LIS长度为$k$的数的个数,$Q \le 10000,L,R < 2^{63}-1,k \le 10$. 首先肯定是数位DP.然后考虑怎么做这个dp.如果把$k$记录到状态 ...
随机推荐
- NSDate 格式化含有毫秒
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSS"]; 版权声明:本文为博主原创文章,未经博主允许不得转载.
- TAE words
love handle pang carbohydrate podiatry splay out Cinderella liposuction mingle fly t ...
- 实现三个div,固定左右两边的div宽为200,中间的div宽度自适应的四种方法
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- 【原生JS】键盘事件
视频播放器音量调节效果. 效果图:“我很丑!~可是我有音乐和啤酒!~” HTML: <!DOCTYPE html> <html> <head> <meta c ...
- SVG和canvas画图,js求数组最大最小值
windows命令行的内容怎么复制,右键选择标记,选中内容后再点击鼠标右键就复制了. 安装Node.js后再用npm install命令会出现如下warn:saveError ENOENT: no s ...
- [转][Linux/Ubuntu] vi/vim 使用方法讲解
vi/vim 基本使用方法 vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器,这里只是简单地介绍一下它的用法和一小部分指令.由于对Unix及Linux系统的 ...
- P1106 细胞分裂
题目描述 Hanks博士是BT(Bio-Tech,生物技术)领域的知名专家.现在,他正在为一个细胞实验做准备工作:培养细胞样本. Hanks博士手里现在有 \(N\) 种细胞,编号从 \(1\) 到 ...
- cfp大纲
AFP基础知识 本章共14个考点,考试考15分左右. 本章重点: .职业道德准则 .家庭财务分析:净值的计算.储蓄的计算 .简单的财务比率分析 .金融理财和法律:企业组织形式.夫妻公共财产制度.财产分 ...
- UPC 2019年第二阶段我要变强个人训练赛第六场
传送门 A.上学路线 题目描述 小D从家到学校的道路结构是这样的:由n条东西走向和m条南北走向的道路构成了一个n*m的网格,每条道路都是单向通行的(只能从北向南,从西向东走). 已知小D的家在网格的左 ...
- java 菜单
继承体系 MenuBar,Menu,MenuItem之间的关系: 先创建菜单条,再创建菜单,每一个菜单中建立菜单项. 也可以菜单添加到菜单中,作为子菜单. 通过setMenuBar()方法,将菜单添加 ...