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$记录到状态 ...
随机推荐
- SDUT-2122_数据结构实验之链表七:单链表中重复元素的删除
数据结构实验之链表七:单链表中重复元素的删除 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 按照数据输入的相反顺序(逆 ...
- day3_python之函数返回值、语句形式、表达式形式
一. 函数对象 1. 函数是第一类对象,即函数可以当作数据传递 #1 可以被引用 #2 可以当作参数传递 #3 返回值可以是函数 #3 可以当作容器类型的元素 二.返回值 return的返回值没有类型 ...
- selenium webdriver学习(九)------------如何操作cookies(转)
selenium webdriver学习(九)------------如何操作cookies 博客分类: Selenium-webdriver Web 测试中我们经常会接触到Cookies,一个C ...
- CODE FESTIVAL 2017 qual B D 101 to 010(dp)
除非人品好,能碰巧想到思路,否则基本是做不出来dp的,除了那几个经典的dp模型.. 看了几个前几名的代码,还是t神的代码比较清晰.膜tourist 代码的思路和题解思路基本一致..... #inclu ...
- hdu 1789 Doing Homework again (Greedy)
Problem - 1789 继续贪心.经典贪心算法,如果数据比较大就要用线段树来维护了. 思路很简单,只要按照代价由大到小排序,然后靠后插入即可.RE了一次,是没想到deadline可以很大.如果d ...
- laravel 学习笔记blog后台
https://github.com/almasaeed2010/adminlte composer require "almasaeed2010/adminlte=~2.0"
- 洛谷P4018 Roy&October之取石子 题解 博弈论
题目链接:https://www.luogu.org/problem/P4018 首先碰到这道题目还是没有思路,于是寻思还是枚举找一找规律. 然后写了一下代码: #include <bits/s ...
- SpringBoot使用logback输出日志并打印sql信息 --经典---
最近在学习springboot以及一些springcloud插件的使用,其中发现默认的配置并不能打印一些有用的日志,所以需要自定义一些日志输出方式以便于查看日志排查问题,目前只整理了两种使用方式,如下 ...
- settTimeout vs setInterval
setTimeout:过一段固定的时间后,将代码提交到代码队列中排队. setInterval:每隔一段固定的时间,执行一次代码. 他们两都接受两个参数,第一个参数是字符串或者函数,第二个参数是设定的 ...
- 2018-8-10-win10-uwp-后台获取资源
title author date CreateTime categories win10 uwp 后台获取资源 lindexi 2018-08-10 19:17:19 +0800 2018-2-13 ...