数位统计DP——AcWing 338. 计数问题

2024-06-20 16:28

本文主要是介绍数位统计DP——AcWing 338. 计数问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

数位统计DP

定义

数位DP(Digital DP)是一种用于解决与数字的数位相关问题的动态规划算法。它将数字的每一位看作一个状态,通过转移状态来计算满足特定条件的数字个数或其他相关统计信息。

运用情况

  • 统计满足特定条件的数字个数,例如在给定范围内有多少个数字满足某些数位特征。
  • 计算数字的某个数位上的特定统计信息,如出现的数字频率等。
  • 解决与数字排列、组合相关的问题。

注意事项

  1. 数位DP的核心是正确定义状态和状态转移方程。状态的设计要能够简洁地表示问题的特征,并且状态转移要能够准确地反映数字的数位变化。
  2. 注意边界情况的处理,特别是对于最高位和最低位的特殊处理。
  3. 数位DP通常需要进行记忆化搜索或使用动态规划数组来避免重复计算,以提高效率。
  4. 在实际应用中,要根据具体问题的特点选择合适的数位DP方法,并进行适当的优化和剪枝。

解题思路

  • 分析问题,确定需要统计的数字特征或满足的条件。
  • 设计状态,通常使用一个多维数组来表示不同数位上的状态。
  • 定义状态转移方程,描述如何从一个状态转移到另一个状态。
  • 确定初始状态和边界条件。
  • 使用记忆化搜索或动态规划算法来计算状态值。
  • 根据最终的状态值得到问题的答案。

AcWing 338. 计数问题

题目描述

AcWing 338. 计数问题 - AcWing

运行代码

#include <iostream>
#include <vector>
using namespace std;
int power(int x)
{int res = 1;while(x --) 
res *= 10;return res;
}
int get(vector<int> num, int l, int r)
{int res = 0;for(int i = l; i >= r; i -- ) res = res * 10 + num[i];return res;
}
int count(int n, int x)
{if(n == 0) return 0;vector<int> num;while(n){num.push_back(n%10);n/=10;}n = num.size();int res = 0;for(int i = n - 1 - !x; i >= 0; i --){if(i < n - 1){res += get(num, n - 1, i + 1) * power(i);if(x == 0) res -= power(i);}if(num[i] == x) res += get(num, i - 1, 0) + 1;else if(num[i] > x) res += power(i);}return res;
}
int main()
{int a, b;while(cin >> a >> b, a && b){if(a > b) swap(a, b);for(int i = 0; i < 10; i ++)cout << count(b, i) - count(a - 1, i) << ' ';cout << endl;}return 0;
}

代码思路

  • power 函数:计算 10 的指定次幂。
  • get 函数:从给定的数字数组中,按照指定的范围(从左到右)提取出一个数字。
  • count 函数:这是核心函数,用于计算给定数字 n 中特定数字 x 出现的次数。它通过将数字 n 转换为数字数组,然后从高位到低位进行分析计算。对于每一位,如果该位小于最高位且不等于 x,则加上前面高位构成的数字乘以 10 的相应次幂;如果该位等于 x,则加上低位数字构成的数加 1;如果该位大于 x,则加上 10 的相应次幂。最后返回总的出现次数。
  • 在 main 函数中:不断读取两个数字 a 和 b,如果都不为 0 则进行处理。通过交换确保 a 小于 b,然后对于数字 0 到 9,分别计算在 b 中出现的次数减去在 a-1 中出现的次数,并输出。

改进思路

  1. 简化计数逻辑:当前的count函数实现较为复杂,它通过手动处理每一位数字来统计特定数字x出现的次数。可以考虑简化这一过程,直接遍历范围内的每个数,统计相应数字出现的次数,这可能使逻辑更清晰。

  2. 避免重复计算:注意到count函数对每个数字xab都独立计算了一次,这导致了很多重复的工作,特别是对于连续的整数序列。可以通过计算每个数字在一个数位上的贡献,然后根据位数累加这些贡献,来减少重复计算。

  3. 使用字符串处理数字:将整数转换成字符串处理,在某些情况下可以使代码更加直观简洁,尤其是在需要频繁操作数字的每一位时。

  4. 预计算 powers of 10:当前power10函数在每次调用时都重新计算10的幂,如果在循环外预先计算好所需的10的幂次方数组,可以提高效率。

  5. 优化输入处理:代码中通过if(a > b) swap(a, b);确保了a<=b,但这个条件检查对于解决问题并非必要,因为统计数字出现的次数并不依赖于a和b的顺序。

  6. 利用STL中的容器和算法:比如,可以使用std::unordered_map来存储每个数字出现的次数,利用标准库提供的函数来简化代码。

这篇关于数位统计DP——AcWing 338. 计数问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1078646

相关文章

hdu1496(用hash思想统计数目)

作为一个刚学hash的孩子,感觉这道题目很不错,灵活的运用的数组的下标。 解题步骤:如果用常规方法解,那么时间复杂度为O(n^4),肯定会超时,然后参考了网上的解题方法,将等式分成两个部分,a*x1^2+b*x2^2和c*x3^2+d*x4^2, 各自作为数组的下标,如果两部分相加为0,则满足等式; 代码如下: #include<iostream>#include<algorithm

hdu4826(三维DP)

这是一个百度之星的资格赛第四题 题目链接:http://acm.hdu.edu.cn/contests/contest_showproblem.php?pid=1004&cid=500 题意:从左上角的点到右上角的点,每个点只能走一遍,走的方向有三个:向上,向下,向右,求最大值。 咋一看像搜索题,先暴搜,TLE,然后剪枝,还是TLE.然后我就改方法,用DP来做,这题和普通dp相比,多个个向上

hdu1011(背包树形DP)

没有完全理解这题, m个人,攻打一个map,map的入口是1,在攻打某个结点之前要先攻打其他一个结点 dp[i][j]表示m个人攻打以第i个结点为根节点的子树得到的最优解 状态转移dp[i][ j ] = max(dp[i][j], dp[i][k]+dp[t][j-k]),其中t是i结点的子节点 代码如下: #include<iostream>#include<algorithm

hdu4865(概率DP)

题意:已知前一天和今天的天气概率,某天的天气概率和叶子的潮湿程度的概率,n天叶子的湿度,求n天最有可能的天气情况。 思路:概率DP,dp[i][j]表示第i天天气为j的概率,状态转移如下:dp[i][j] = max(dp[i][j, dp[i-1][k]*table2[k][j]*table1[j][col] )  代码如下: #include <stdio.h>#include

usaco 1.1 Broken Necklace(DP)

直接上代码 接触的第一道dp ps.大概的思路就是 先从左往右用一个数组在每个点记下蓝或黑的个数 再从右到左算一遍 最后取出最大的即可 核心语句在于: 如果 str[i] = 'r'  ,   rl[i]=rl[i-1]+1, bl[i]=0 如果 str[i] = 'b' ,  bl[i]=bl[i-1]+1, rl[i]=0 如果 str[i] = 'w',  bl[i]=b

uva 10154 DP 叠乌龟

题意: 给你几只乌龟,每只乌龟有自身的重量和力量。 每只乌龟的力量可以承受自身体重和在其上的几只乌龟的体重和内。 问最多能叠放几只乌龟。 解析: 先将乌龟按力量从小到大排列。 然后dp的时候从前往后叠,状态转移方程: dp[i][j] = dp[i - 1][j];if (dp[i - 1][j - 1] != inf && dp[i - 1][j - 1] <= t[i]

uva 10118 dP

题意: 给4列篮子,每次从某一列开始无放回拿蜡烛放入篮子里,并且篮子最多只能放5支蜡烛,数字代表蜡烛的颜色。 当拿出当前颜色的蜡烛在篮子里存在时,猪脚可以把蜡烛带回家。 问最多拿多少只蜡烛。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cs

uva 10069 DP + 大数加法

代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <queue>#include <map>#include <cl

uva 10029 HASH + DP

题意: 给一个字典,里面有好多单词。单词可以由增加、删除、变换,变成另一个单词,问能变换的最长单词长度。 解析: HASH+dp 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#inc

XTU 1233 n个硬币连续m个正面个数(dp)

题面: Coins Problem Description: Duoxida buys a bottle of MaiDong from a vending machine and the machine give her n coins back. She places them in a line randomly showing head face or tail face o