寒假思维训练day21

今天更新一道不错的状态压缩DP题,顺带总结一下状态压缩DP。


                                        摘要:

                                               Part1   浅谈状态压缩DP的理解

                                               Part2   浅谈对状态机DP的理解

                                               Part3   关于状态压缩DP的1道例题


Part1  状态压缩DP

1、状态压缩DP:

事物的状态可能包含多个特征,但是事物的状态之间却可以互相转移,此时我们引入状态压缩DP,将事物的复杂的状态用一个数字来替代,此时事物的状态可以用数组的某个位置表示,从而可以进行状态的转移。

2、常见的状态表示:

(1) 用10进制数字本身表示状态,比如表示当前状态%某个数字的余数等等,这里举一个例子。
(2) 用10进制内蕴含的二进制位表示状态, 01, 表示了每个位置上的两种状态,它既可以表示是否存在,也可以表示数量的奇偶性。

(3) 用10进制内蕴含的K进制(除了10进制和2进制外的其它进制)表示状态,这种题我没见过,但是基于上面我们很容易可以推广。

3、什么时候我们可以用:

首先是在你的状态表示基础上,整体的转移图是一个拓扑图,也就是可以通过递推得来,并且时间空间可以过得去,此时我们就可以用状态压缩DP。


Part2 状态机DP

我在之前写过一篇关于状态机DP的文章,里面有详细的理论和几道很好的例题:

http://t.csdnimg.cn/POtFs


Part3  例题: 小红的回文数

题目链接:E-小红的回文数_牛客周赛 Round 32 (nowcoder.com)

(1)题意:

小红定义一个整数是“好数”,当且仅当该整数通过重排之后可以形成回文数。(可以包含前导零)现在小红拿到了一个正整数x,小红想截取一段连续区间得到好数,她想知道有多少种不同的方案? 1<= x <= 10^{10^5}


(2)题解: 

暴力显然会超时,必定需要n * n 的复杂度,此时我们不妨考虑一下DP,  我们此时从左到右去考虑这个数,我们考虑每个以第i位数结尾的情况,最后答案就是累加后的值,我们此时考虑一下以第i位数结尾的区间,我们发现对于一个数字而言,每位的数字只能是0-9的数字之一,我们不妨用10个二进制位表示每一种数字的数量%2是多少,这样我们就可以通过统计1的个数判断有几个奇数,如果要构造一个回文串,显然只能由一个或者0个奇数的位。
状态转移方程:F[i][state],表示以第i位数结尾的数字区间,且0-9各个的数字情况是state的方案数,F[i][state1] = F[i - 1][state1 \oplus (1 << a[i])],并且对于每个位单独一位的情况也要考虑,所以状态转移代码是: 

    vector<vector<int>> dp(n + 1, vector<int>((1 << 10) + 2)); dp[0][0] = 1;  for(int i = 1; i <= n; i ++ ) {for(int j = 0; j < (1 << 10); j ++ ) {int k = j ^ (1 << (s[i - 1] - '0'));dp[i][k] += dp[i - 1][j]; }if(i >= 2) dp[i][1 << (s[i - 1] - '0')] ++; }

你以为事情结束了吗,这是一道比较毒瘤的题,它会卡你的空间,在此基础上我们需要引入滚动数组优化,优化掉一维的空间。
此时的转移代码是:

    dp[0] = 1;  long long res = 0; for(int i = 1; i <= n; i ++ ) {memset(usdp, 0, sizeof usdp); for(int j = 0; j < 1 << 10; j ++ ) usdp[j ^ (1 << (s[i - 1] - '0'))] += dp[j];if(i >= 2) usdp[1 << (s[i  - 1] - '0')] ++; for(int j = 0; j < 1 << 10; j ++ ) {cnt = 0; for(int c = 0; c <= 9; c ++ ) if(j >> c & 1) ++ cnt; if(cnt <= 1) res += usdp[j]; dp[j] = usdp[j]; }}cout << res << endl; 

(3) 代码 (C ++):

滚动数组优化:
 

#include <bits/stdc++.h>
// #define int long long 
#define lowbit(x) (x&-x)
using namespace std; 
const int N = 1e5 + 2; 
const int inf = 0x3f3f3f3f; 
int n, cnt; 
long long dp[2025], usdp[2025];  
// int a[N]; 
void solve() {string s; cin >> s; n = s.size();cnt = 0; 
//     for(int i = 1; i <= n; i ++ ) a[i] = s[i - 1] - '0';  dp[0] = 1;  long long res = 0; for(int i = 1; i <= n; i ++ ) {memset(usdp, 0, sizeof usdp); for(int j = 0; j < 1 << 10; j ++ ) usdp[j ^ (1 << (s[i - 1] - '0'))] += dp[j];if(i >= 2) usdp[1 << (s[i  - 1] - '0')] ++; for(int j = 0; j < 1 << 10; j ++ ) {cnt = 0; for(int c = 0; c <= 9; c ++ ) if(j >> c & 1) ++ cnt; if(cnt <= 1) res += usdp[j]; dp[j] = usdp[j]; }}cout << res << endl; }
int main() {ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int ts = 1; 
//     cin >> ts; while(ts -- ) solve(); return 0; 
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/468508.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

伦敦金是现货黄金吗?

伦敦金属现货黄金交易的一种形式。投资者可以通过伦敦金市场直接买卖黄金&#xff0c;以实现投资收益。伦敦金市场具有高度流动性和透明度&#xff0c;是全球投资者广泛参与的贵金属交易市场之一。 什么是现货黄金&#xff1f; 现货黄金是指实物黄金的交易&#xff0c;投资者可…

【STM32 CubeMX】HAL库的本质读写寄存器

文章目录 前言一、HAL库的本质1.1 HAL库的本质是操作寄存器1.2 自己实现HAL_GPIO_WritePin寄存器通过寄存器的操作点灯代码概况Port bit set/reset register寄存器 总结 前言 在嵌入式系统开发中&#xff0c;HAL&#xff08;Hardware Abstraction Layer&#xff09;库是一个重…

算法沉淀——哈希算法(leetcode真题剖析)

算法沉淀——哈希算法 01.两数之和02.判定是否互为字符重排03.存在重复元素04.存在重复元素 II05.字母异位词分组 哈希算法&#xff08;Hash Algorithm&#xff09;是一种将任意长度的输入&#xff08;也称为消息&#xff09;映射为固定长度的输出的算法。这个输出通常称为哈希…

CTFshow web(php命令执行59-67)

web59 <?php /* # -*- coding: utf-8 -*- # Author: Lazzaro # Date: 2020-09-05 20:49:30 # Last Modified by: h1xa # Last Modified time: 2020-09-07 22:02:47 # email: h1xactfer.com # link: https://ctfer.com */ // 你们在炫技吗&#xff1f; if(isset($_POST…

docker 2:安装

docker 2&#xff1a;安装 ‍ ubuntu 安装 docker sudo apt install docker.io‍ 把当前用户放进 docker 用户组&#xff0c;避免每次运行 docker 命都要使用 sudo​ 或者 root​ 权限。 sudo usermod -aG docker $USER​id $USER ​看到用户已加入 docker 组 ​​ ‍ …

SCI 1区论文:Segment anything in medical images(MedSAM)[文献阅读]

基本信息 标题&#xff1a;Segment anything in medical images中文标题&#xff1a;分割一切医学图像发表年份: 2024年1月期刊/会议: Nature Communications分区&#xff1a; SCI 1区IF&#xff1a;16.6作者: Jun Ma; Bo Wang(一作&#xff1b;通讯)单位&#xff1a;加拿大多…

随机过程及应用学习笔记(二)随机过程的基本概念

随机过程论就是研究随时间变化的动态系统中随机现象的统计规律的一门数学学科。 目录 前言 一、随机过程的定义及分类 1、定义 2、分类 二、随机过程的分布及其数字特征 1、分布函数 2、数字特征 均值函数和方差函数 协方差函数和相关函数 3、互协方差函数与互相关函…

Spring 如何解决循环依赖?Spring三级缓存

什么是循环依赖 说白是一个或多个对象实例之间存在直接或间接的依赖关系&#xff0c;这种依赖关系构成了构成一个环形调用。 自己依赖自己 两个对象间的依赖关系 多个对象间的依赖关系 Spring出现循环依赖的场景 单例的setter注入 Service public class A {Resourceprivate…

深刻反思现代化进程:20世纪与21世纪的比较分析及东西方思想家的贡献

深刻反思现代化进程&#xff1a;20世纪与21世纪的比较分析及东西方思想家的贡献 摘要&#xff1a;随着人类社会的快速发展&#xff0c;现代化已成为全球范围内的普遍追求。然而&#xff0c;20世纪至21世纪的现代化进程并非一帆风顺&#xff0c;它伴随着环境破坏、社会不平等和文…

Ubuntu 23.10通过APT安装Open vSwitch

正文共&#xff1a;888 字 8 图&#xff0c;预估阅读时间&#xff1a;1 分钟 先拜年&#xff01;祝各位龙年行大运&#xff0c;腾跃展宏图&#xff01; 之前在介绍OpenStack的时候介绍过&#xff08;什么是OpenStack&#xff1f;&#xff09;&#xff0c;OpenStack是一个开源的…

【DDD】学习笔记-订单核心流程的事件风暴

现在&#xff0c;我们针对电商领域的订单核心流程开展事件风暴工作坊&#xff0c;以此来获得我们的领域分析模型。 工作坊准备 要开展好事件风暴工作坊&#xff0c;需得具备天时地利人和。 天时地利人和 天时。需得安排好专门的时间来一个为期多天的事件风暴。事件风暴很难…

Ambiguous Medical Image Segmentation using Diffusion Models利用扩散模型分割模糊医学图像

摘要&#xff1a; 事实证明&#xff0c;在临床任务中&#xff0c;来自一组专家的集体见解总是优于个人的最佳诊断。对于医学图像分割任务&#xff0c;现有的基于人工智能的替代研究更多地侧重于开发能够模仿最佳个体的模型&#xff0c;而不是利用专家组的力量。 在本文中&…