一本通提高篇之数位DP

目录

暴力做法

爆搜做法

数字计数

        恨7不成妻 


 

暴力做法

暴力枚举每个数字是否符合要求,时间复杂度O(n),超时。

爆搜做法

逐位填数字0~9,遇到不合法就剪枝,记忆化绝不超时。

记忆化f[k][x][p]表示填到第k为,上一位是x,当前是否可以随便填,后面的方案数。

其中,p=0可以不记忆化,因为此时只有一种情况,就是每一位都跟n的对应位相等,不记忆化也不超时。

如果记忆化含有p,那么每次都需要memset数组,多组数据效率会降低。

如果记忆化不含p,那么多组数据不需要每次memset数组,因为后面都可以随便填,不同组数据方案数是一样的。

数字计数

 

恨7不成妻 

平方和求法(类似方差公式推导):

低位平方和为v,数量为c,数字之和为s。

高1位平方和位V,数量为C,数字之和为S。

新增部分:原来每个符合要求的低位数字a,增加j(高位权值)后是新数,求新数平方和。

(j+a)2=j2+2ja+a2(j+a)2=j2+2ja+a2,共有c个,所以需要加上c∗j2+2js+vc∗j2+2js+v

高位填入0~9,数量直接累加即可,0表示累加低位数量;和也一样,只是还需要加上高位权值之和。

 

### 关于数的计数问题 在解决数的计数问题时,常会涉及递归、动态规划或者搜索算法。以下是基于题目描述的一种用解决方案。 #### 输入处理 假设输入数据为多行浮点数,代表白细胞的数量单位 \(10^9/\text{L}\),可以过读取标准输入流并解析每一行的数据来完成初步处理[^1]。具体实现如下: ```python data = [] for _ in range(n): # n 表示总行数 line = input().strip() numbers = list(map(float, line.split())) data.extend(numbers) ``` 上述代码片段实现了逐行读入数据并将所有数值存储在一个列表 `data` 中。 --- #### 计数逻辑设计 对于计数类问题,可以采用深度优先搜索 (DFS) 或广度优先搜索 (BFS) 来遍历可能的状态空间。例如,在信息学奥赛中提到的字母访问状态跟踪方法,可以用一个整型变量 `visited` 的每一位表示某个特定条件是否被满足[^2]。 以下是一个简单的 DFS 实现框架用于统计符合条件的结果数目: ```python def dfs(current_state, visited_states): if current_state >= len(data): # 边界条件:超出范围则返回 return 0 count = 0 for i in range(len(data)): if not (visited_states & (1 << i)): # 如果该位置未被访问过 new_visited = visited_states | (1 << i) # 更新已访问标记 count += dfs(i, new_visited) # 继续向下探索 return count + 1 # 当前路径有效,则计入总数 result = dfs(0, 0) # 初始调用 print(result) ``` 此代码过按位操作记录哪些索引已经被访问,并利用递归来穷举所有的可能性组合。 --- #### 动态规划优化 当问题规模较大时,纯暴力枚举可能会超时。此时可引入记忆化技术或完全转换成动态规划形式。定义状态转移方程如下: \[ dp[i][mask] \] 其中 \(i\) 是当前考虑的位置,\(mask\) 是一个二进制掩码用来保存已经选中的元素集合。初始状态下 \(dp[0][0]=1\) ,最终目标是从任意起点出发到达终点的所有合法方案数。 更新规则为: \[ dp[j][new\_mask] += dp[i][old\_mask], \quad j \in \text{{unvisited neighbors of }} i \] 完整 DP 版本如下所示: ```python from functools import lru_cache @lru_cache(None) def dp(position, mask): if position == len(data): # 所有位置均已被覆盖 return int(mask == (1 << len(data)) - 1) total = 0 for next_pos in range(len(data)): if not (mask & (1 << next_pos)): # 下一跳尚未访问 total += dp(next_pos, mask | (1 << next_pos)) return total answer = sum(dp(start, 1 << start) for start in range(len(data))) print(answer) ``` 此处运用了 Python 自带装饰器 @lru_cache 对中间计算结果进行缓存以减少重复运算次数。 --- ### 总结 以上分别介绍了针对此类计数问题的基础解法以及更高效的改进策略。实际应用过程中需视具体情况调整参数设定与边界判定准则。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值