HDU - 4352 数位dp
来源:互联网 发布:宿州淘宝xinsuzhou 编辑:程序博客网 时间:2024/05/21 06:36
题意:
定义一个数的power值就是这个数数位上严格递增子序列的长度,找出区间 [L,R] 中 POWER == k 的数的个数。
思路:
好题,搜题意的时候看到了状态压缩四个字的提示,如果没有这个提示感觉应该想不到这点。
很巧妙地思路,之前没有想过LIS还可以运用状压,这题的关键在于数位上的严格上升子序列最多只有10个,这是可以用状态压缩表示的。
如何利用状压求解LIS,关键要深刻理解LIS的二分求解方法。
回忆一下二分的求解方式,dp[i]表示的是长度为i的LIS末尾数的最小值,因为同样长度的LIS,很显然是末尾越小越好,这样能被后面数字利用的机会就越大。所以用这样的状态描述。这样遍历数组,当遇到a[i]时,这里需要找到dp数组中第一个比a[i]大的数的位置pos,然后用a[i]来代替这个位置上的值,也就更新长度为pos的LIS的末尾值,使之更小。
举个例子:
数组a[5] ; 4,2,3,1,5
dp数组初始化: INF, INF, INF, INF, INF
而后dp数组的变化如下:
插入4: 4, INF, INF, INF ,INF
插入2: 2, INF, INF, INF, INF
插入3: 2, 3, INF, INF, INF
插入1: 1, 3, INF, INF, INF
插入5: 1, 3, 5, INF, INF
dp数组最后INF前的长度为3,所以数组a的LIS长度就是3。这个思路就是解决本题的关键。
利用状态state(1 << 10) 来代替上面的dp数组,每次枚举一个数位i,也就和上面一样的操作。但是这里由于LIS最长也就是10,state表示的就是当前dp上的数出现的情况,比如最后1,3,5用state表示就是101010(右端低位),之所以可以这样表示,是因为上面介绍的dp数组有一个很重要的特性,那就是单调递增,这样我们只保存数位出现的情况,也就不需要保存各个数位的顺序了,因为都是递增的,所以直接按照数位的顺序理解就可以了。
有了这个状压的思路,剩下的就是数位dp了,注意前导零的处理。
代码:
#include <bits/stdc++.h>using namespace std;typedef long long ll;const int MAXN = (1 << 10) + 10;int a[20];ll dp[20][12][MAXN];int get_state(int sta, int x) { // 根据枚举的数字得到新的状态 for (int i = x; i < 10; i++) { if (sta & (1 << i)) { sta ^= (1 << i); break; } } sta |= (1 << x); return sta;}int cal(int sta) { // 计算数位中的1的个数,也就是LIS的长度 int cnt = 0; while (sta) { if (sta & 1) ++cnt; sta >>= 1; } return cnt;}ll dfs(int pos, int len, int state, bool limit) { if (len < 0) return 0; if (pos == -1) return len == 0 ? 1 : 0; if (state && !limit && dp[pos][len][state] != -1) return dp[pos][len][state]; int up = limit ? a[pos] : 9; ll res = 0; for (int i = 0; i <= up; i++) { if (i == 0 && state == 0) res += dfs(pos - 1, len, state, limit && a[pos] == i); else { int nstate = get_state(state, i); int cnt = cal(nstate) - cal(state); res += dfs(pos - 1, len - cnt, nstate, limit && a[pos] == i); } } if (state && !limit) dp[pos][len][state] = res; return res;}ll solve(ll x, int k) { int pos = 0; while (x) { a[pos++] = x % 10; x /= 10; } return dfs(pos - 1, k, 0, true);}int main() { int T, cs = 0; scanf("%d", &T); memset(dp, -1, sizeof(dp)); while (T--) { int k; ll l, r; scanf("%I64d%I64d%d", &l, &r, &k); printf("Case #%d: %I64d\n", ++cs, solve(r, k) - solve(l - 1, k)); } return 0;}
0 0
- hdu 4352 数位DP
- hdu 4352 数位DP
- HDU 4352 数位dp
- HDU - 4352 数位dp
- HDU-4352-数位dp,LIS
- HDU 4352 数位DP + LIS
- 【HDU】4352 XHXJ's LIS 数位DP
- 【数位DP】【hdu 4352】XHXJ's LIS
- HDU 4352 XHXJ's LIS 数位dp
- HDU 4352 XHXJ's LIS(数位DP)
- hdu 4352 XHXJ's LIS(数位dp)
- HDU 4352 XHXJ's LIS【数位DP】
- hdu 4352 状态压缩+数位DP
- hdu 3555 数位dp
- hdu 3555 数位dp
- HDU 3652 数位DP
- HDU 3555 数位DP
- HDU 3555 \数位DP
- 蓝桥杯 历届试题 危险系数 两点间割点法 By Assassin
- 3U VPX DSP+FPGA 处理板
- cmd命令行激活win7
- ffmpeg实现音频resample(重采样)
- github上关于iOS的各种开源项目集合(转)
- HDU - 4352 数位dp
- 医疗行业某集团公司财务系统迁移阿里云的案例分享
- 解决React Native中ScrollView中控件获得焦点及点击空白处键盘消失的问题
- react-native 踩过的坑
- kafka之一 入门介绍
- java web中如何使用将数据写入CSV文件中并下载
- 蓝桥杯算法提高 拿糖果
- Spring JDBC 具名参数
- insert时返回键值