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$记录到状态 ...
随机推荐
- 一线实践 | 借助混沌工程工具 ChaosBlade 构建高可用的分布式系统
在分布式架构环境下,服务间的依赖日益复杂,可能没有人能说清单个故障对整个系统的影响,构建一个高可用的分布式系统面临着很大挑战.在可控范围或环境下,使用 ChaosBlade 工具,对系统注入各种故障, ...
- @codechef - BIKE@ Chef and Bike
目录 @description@ @solution@ @accepted code@ @details@ @description@ 输入 n(n ≤ 22) 个点,m(m ≤ 8000) 个边.每 ...
- H3C TCP与UDP的对比
- jq实现超级简单的隔行变色
文章地址:https://www.cnblogs.com/sandraryan/ <!DOCTYPE html> <html lang="en"> < ...
- vue iframe嵌套页面高度自适应 (ios 宽度扩大的bug , ios展示比例问题)
<template> <div class="card-index pt-relative"> <div id="wrapper ...
- java io流与序列化反序列化
java的io是实现输入和输出的基础,可以方便的实现数据的输入和输出操作. 序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程.在序列化期间,对象将其当前状态写入 ...
- Python--day60--一个简单(不完整)的web框架
- 2018-8-10-如何入门-C++-AMP-教程
title author date CreateTime categories 如何入门 C++ AMP 教程 lindexi 2018-08-10 19:16:51 +0800 2018-2-13 ...
- 2018-7-31-C#-判断两条直线距离
title author date CreateTime categories C# 判断两条直线距离 lindexi 2018-07-31 14:38:13 +0800 2018-05-08 10: ...
- H3C DHCP简介