和与或

给你一个数组R,包含N个元素,求有多少满足条件的序列A使得
0 ≤ A[i] ≤ R[i]
A[0]+A[1]+...+A[N-1]=A[0] or A[1]... or A[N-1]
输出答案对1e9+9取模

输入描述:

第一行输入一个整数N (2 ≤ N ≤ 10)
第二行输入N个整数 R[i] (1 ≤ R[i] ≤ 1e18)

输出描述:

输出一个整数

示例1

输入

2 3 5

2
3 5

输出

15

15

示例2

输入

3 3 3 3

3
3 3 3

输出

16

16

示例3

输入

2 1 128

2
1 128

输出

194

194

示例4

输入

4 26 74 25 30

4
26 74 25 30

输出

8409

8409

示例5

输入

2 1000000000 1000000000

2
1000000000 1000000000

输出

420352509

420352509

备注:

子任务1: n <= 3
子任务2: n <= 5
子任务3: 无限制

分析:题目分析,转化

节选自牛客网题解

算了,自己想想怎么组织语言

我们拿几个数去试试,比如4+0=4|0,4+3=4|3,等等,可以发现,全部看成二进制数加法和取或,那么求和时候不会出现进位。下面,如此分析,求和时候如果记数组a的所有元素的和是sum,那么,对于sum二进制表示的各位数,sum二进制表示是---------------,每个横线表示一个数(0或者1),对于第p位数,如果该数是1,那么a中所有的元素,有且只能有一个元素第p位都要是1,其他的都要是0;如果该数是0,那么a中所有元素的第p位都要是0.

本题求的是满足和等于或且分别小于另一个数组对应位置元素等条件的数组a的个数,我们可以转化成,满足一个数sum,将其各个位分给数组a,且如果分的那一位上数字是1的话,只分给数组a的一个元素的相应数位上(保证不进位),同时注意到,只分给数组a的一个元素的那个元素,是有条件的,首先,那个数位上的1分给a中的那个元素,要满足小于数组r中相应元素的条件,a中有的元素有的只能分到0,而不能分到1(如上述,分到1就不满足小于r中对应元素的限制了),所以,我们很关注怎么描述这种限制。

对于上面的限制,我们需要仔细分析

对于数sum(a数组元素的和),我们考察sum的第p位,同时,由上面的分析,数组a的元素的第p位在求和时不能产生进位,所以我们也要考察数组a所有元素的第p位,进一步,我们限制条件里有数组r,所以我们也需要考虑数组r所有元素的第p位,另外,我们不要忘了,当前状态下(动态规划都是有状态的,可以认为是当前这一种情况下)数组a各个元素的限制状态的情况是什么,我们用int变量limit存储,limit的二进制表示的第i位是1,表示当前情况下数组a中元素a[i]的第p位没有限制(无论取1还是取0都不会使a[i]的值超过对应的r[i]),看到这里,可能会想,对于第p位,limit都存储了当前的数组a各个元素的限制,还要数组r干什么,数组r存储的数是数组a各个元素的最大值,用于求解数sum的第p-1位时数组a各个元素的限制。

******************************************************************************************************

写到这里,觉得我写的还是不是很好理解,还是贴上牛客上的题解:

分析 :题目要求 A1+A2+A3…+AN=A1|A2|A3…|AN ,把|运算符用+号来表示,A1|A2=A1+A2-2*(A1&A2),可以推出,把A1-AN转化成二进制表达后,同一位二进制位上不能有两个以上的1,不然一定会出现式子里的减法从而小于A1+A2…+AN,我们不妨设SUM为所有A数组的和,然后把SUM转化成二进制,条件就被我们转化成,SUM二进制上的 1 只会来源于N个Ai中的一个,根据这个设计DP的状态表示。

状态表示:DP[iI[j](i=62,j=1<<12)表示枚举到sum二进制的第i位时,R数组里各个数字的限制情况,这里特别解释下限制的意思,因为我们枚举SUM二进制时要考虑二进制上1的来源,设R1=10010(二进制),如果SUM的第五位是由A1的数字贡献的,既A1>=10000,那么当我们继续考虑第四位的1时,A1必然无法继续作出贡献,会导致A1超出R1的限制,直到枚举至第二位,它本身上界有1时,才能继续贡献,可是如果之前第5位的时候A1不贡献1,那么根据二进制,高位的1大于所有比它低位的1的和(10000>01111),既A1<10000,那么在考虑后面4,3,2,1位的时候,A1可以任意选择贡献1还是不贡献1,这就是限制与不限制的区别。至此J的含义已经清楚 J可以被当成一个12位的二进制数,如果第一位上是1则代表,A1是不受限制的,反之则受限,受限的Ai只能在其上届Ri有1的时候才能作出贡献。

转移方程:假设枚举到第I位,限制状态是J,如果SUM该位二进制数取0,则在该位上是1的R[i],在之后的搜索中全部变成无限制,而如果取1,1的来源有两种情况,一种是R[I]被限制了,但这一位上有1,那么R[I]依旧保持限制,其他这一位上有1的变为无限制,第二种是R[I]没被限制,那么R[I]保持无限制,其他这一位上有1的也为无限制。当然之前就已经无限制的数字在之后依旧无限制,总计三种情况,记忆化搜索。

借鉴的题解如上

*************************************************************************************************************

限制的解除实际上就是这里的难点

我们定义int dfs(int p,int limit),这个函数是干什么的,对于编写的函数,我们有名字,有返回值,有参数,最重要的是,理解函数的功能,该函数的功能是,假设对于数sum(我们要求的就是所有满足条件的数组a的个数,就是把数sum各位分配到合法数组a各个元素上的方案数) ,我们已经分配好了第最高位到第p+1位上的数至数组a各个元素的第最高位至第p+1位,现在,我们需要分配sum数的第p位到数组a各个元素的第p位,此时数组a的个元素的第p位限制情况以二进制形式存储在数limit中(就是说,limit的二进制表示的第i位数表示数组a中元素a[i]第p位的约束情况,limit的二进制表示的第i位数是0,表示数组a中元素a[i]第p位的受到约束,就是说这此时是有限制的,如果a[i]第p位取1(当然要能取1才取1),那么a[i]的第p-1位就不能随便取(限制继续传下去了),否则可能超过r[i]),对于其他的a[j],j不等于i,那么由于a数组只能有一个元素第p位取1,所以a[j]的第p位实际上取0,所以a[j]的第p-1位可以随意取值,不受限制;limit的二进制表示的第i位数是1,表示数组a中元素a[i]第p位的不受约束,就是说a[i]第p位取1也不会超过r[i],可以随意取,那么a[i]的第p-1位也不受限制(不受限制继续传下去了),当前函数是从第p位开始分配sum的数位,直到分配到第0位,所有满足条件的数组a的个数和。

对于sum的第p位,可以取0可以取1,总个数是取0和取1的加和。

当sum第p位取0时,不管数组a各元素有无限制,反正都是只能取0,那么下一位(第p-位上)如果r[i]的第p位是1,相应第p-1位时,a[i]的第p-1位不受限制,反正不会超过r[i],所以下次第p-1位,解除r[i]第p位是1的元素a[i]的限制

当sum第p位取1时,当a[i]有限制时,如果r[i]第p位是0,显然sum第p位的1不能由这个a[i]来贡献了;当a[i]有限制时,如果r[i]第p位是1,sum第p位的1能由这个a[i]来贡献,且这种限制仍然传递到第p-1位上a[i]的限制(不限制就可能超过r[i]),其他的a[j],j不等于i,如果r[j]的第p位是1,那么下一位第p-1位a[j]解除限制;当a[i]无限制时,那么第p-1位a[i]依然无限制,其他的a[j],如果本来有限制,但是r[j]的第p位是1,则第p-1位时a[j]解除限制。

当sum第p位取1时,当a[i]有限制时,如果r[i]第p位是0,显然sum第p位的1不能由这个a[i]来贡献了;当a[i]有限制时,如果r[i]第p位是1,sum第p位的1能由这个a[i]来贡献,且这种限制仍然传递到第p-1位上a[i]的限制(不限制就可能超过r[i]),其他的a[j],j不等于i,如果r[j]的第p位是1,那么下一位第p-1位a[j]解除限制;当a[i]无限制时,那么第p-1位a[i]依然无限制,其他的a[j],如果本来有限制,但是r[j]的第p位是1,则第p-1位时a[j]解除限制。

可以看出,dfs(p,limit)探讨的是,从第p位开始分配sum数至数组a的元素中,这里所有的基本操作都是建立在数的第p位的基础上的,limit说的也是当前第p位上a数组元素的限制,(认为从第最高位开始到第p+1位都已经分配好了,dp[i][j]表示的是,从第p位开始分配sum数,且数组a的限制情况存储在j中,的所有满足情况的数组a的个数

不要忘了取余,不要忘了1l<<p, (long long 1<<p)是先将1强制转换为long long,再左移p位

#include<iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int mod = 1e9+9;int dp[63][1 << 12];
long long R[12];
int n;
int dfs(int p, int limit) {if (p < 0)return 1;if (dp[p][limit] != -1)return dp[p][limit];int ans = 0;//记录r元素第p位上是否有1for (int i = 1; i <= n; i++)if ( R[i] & ((long long)1<<p) )//取出r中每个元素的第p位的值ans |= (1 << i);long long res = 0;//ans分类讨论,sum的第p位可以取0可以取1,两种情况加和//sum第p位取0的话直接进入sum第p-1位的求解讨论,解除限制//sum第p位取1的话,需要看每个r元素是否受限,没有受限,该元素仍不受限且解除其他受限的r元素//***********************************受限,该元素仍受限,解除其他元素受限res += dfs(p - 1, ans|limit  );//sum第p位取0for (int i = 1; i <= n; i++)//sum第p位取1{if ((1 << i) & limit)res += dfs(p - 1, ans| limit );elseif (!((1<<i)&limit)&&ans & (1 << i))res += dfs(p - 1, (ans ^ (1 << i)) | (limit));}dp[p][limit] = res % mod;return dp[p][limit];
}
int main() {memset(dp, -1, sizeof(dp));cin >> n;for (int i = 1; i <= n; i++)scanf("%lld", &R[i]);dfs(61, 0);cout << dp[61][0] << endl;return 0;
}

另附一个链接数位dp总结 之 从入门到模板_wust_wenhao的博客-CSDN博客_数位dp模板for(int i=le;i<=ri;i++) if(right(i)) ans++;基础篇数位dp是一种计数用的dp,一般就是要统计一个区间[le,ri]内满足一些条件数的个数。所谓数位dp,字面意思就是在数位上进行dp咯。数位还算是比较好听的名字,数位的含义:一个数有个位、十位、百位、千位......数的每一位就是数位啦!之所以要引入数位的概念完全就是为了dp。https://blog.csdn.net/wust_zzwh/article/details/52100392

补充一句,注意到前缀和,注意到该数位dp中说的solve(re)-solve(le-1),和前缀和类似,标记一下

动态规划--数位dp--二进制状态压缩相关推荐

  1. 【AcWing】数位统计DP、树形DP、状态压缩DP、记忆化搜索

    [AcWing]数位统计DP.树形DP.状态压缩DP.记忆化搜索 一.数位统计DP 二.状态压缩DP 三.树形DP 四.记忆化搜索 一.数位统计DP 计数问题 给定两个整数 a 和 b,求 a 和 b ...

  2. 提高篇 第五部分 动态规划 第4章 状态压缩类动态规划

    例1 骑士(Sgu223) 1592:[例 1]国王 信息学奥赛一本通(C++版)在线评测系统 https://blog.csdn.net/guoyangfan_/article/details/82 ...

  3. 【基本算法】 位运算:二进制状态压缩

    二进制状态压缩 二进制状态压缩,是指将一个n位的 bool 数组用 n 位的二进制数表示的方法. OP 运算 取出 n 在二进制表示下的第k位 (n >> k) & 1 取出 n ...

  4. 《算法竞赛进阶指南》打卡-基本算法-AcWing 94. 递归实现排列型枚举:dfs、二进制状态压缩

    文章目录 题目解答 题目来源 题目解答 分析: dfs求全排列,这里是用二进制状态压缩进行优化,二进制状态压缩,顾名思义,每个状态是用二进制的某一位表示.这里的体现是state这个状态,它的每一位代表 ...

  5. 《算法竞赛进阶指南》打卡-基本算法-AcWing 92. 递归实现指数型枚举:递推与递归、二进制状态压缩、dfs

    文章目录 题目解答 题目链接 题目解答 分析: 优化:用二进制状态压缩,也就是用二进制上的位来记录数有没有被用过. ac代码 #include<bits/stdc++.h> using n ...

  6. 动态规划(5)状态压缩dp

    一.概述 动态规划的过程是随着阶段不断增长,在每个状态维度上不断扩展.在任意时刻,已经求出最优解的状态与尚未求出最优解的状态在各维度上的分界点组成了dp扩展的轮廓,对于某些问题,我们需要在动态规划的状 ...

  7. 状压DP Hiho-1044 状态压缩

    状态压缩 [HihoCoder - 1044] 小Hi和小Ho在兑换到了喜欢的奖品之后,便继续起了他们的美国之行,思来想去,他们决定乘坐火车前往下一座城市--那座城市即将举行美食节! 但是不幸的是,小 ...

  8. 动态规划 —— 数位 DP

    [概述] 数位 DP 实际是一种计数用的 DP,一般就是统计一个区间 [le,ri] 内满足一些条件数的个数. 所求的限定条件往往与数的位数有关,例如:数位之和.指定数码个数.数的大小顺序分组等. 题 ...

  9. 皮卡丘的梦想2(线段树+二进制状态压缩)

    Description 一天,一只住在 501 实验室的皮卡丘决定发奋学习,成为像 LeiQ 一样的巨巨,于是他向镇上的贤者金桔请教如何才能进化成一只雷丘. 金桔告诉他需要进化石才能进化,并给了他一个 ...

  10. hdu2553 N皇后问题【二进制状态压缩基础】

    rt,二进制压缩的入门题,依旧卡了一个多小时,还不算之前看的那一遍orz 本题要求行列两个斜线都不能多于一个,就算是一行一行遍历,也需要考虑状态的转移方法及记录转移的方法,那么,二进制华丽丽的出场啦~ ...

最新文章

  1. MPB:中国地大侯卫国组-​ 针对热泉原位培养矿物的低质量DNA提取方法
  2. codecomb 2091【路径数量】
  3. C#编写运行在Linux环境下的采用Mediainfo来获取多媒体文件信息的代码
  4. 浮点数在计算机中存储方式float,double)---转
  5. Spring的定时任务
  6. Android开发中常见的内存泄露案例以及解决方法总结
  7. WINDOWS上传文件到LINUX中文乱码
  8. LR录制脚本后,中文显示的是乱码,怎么解决?
  9. hdu1023-----卡特兰数
  10. python处理出租车轨迹数据_基于出租车GPS轨迹数据的研究:出租车行程的数据分析...
  11. Makefile教程
  12. 深度linux deepin15.2,从其它Deepin版本升级到深度Deepin 15.11操作系统的方法
  13. 2012年8月版:Oracle数据库技术更新…
  14. 手机扫描条形码二维码原理和实现等网上资料整理
  15. 【离散数学】编程练习:求关系的传递闭包
  16. 再见2022,你好2023:八年程序媛老兵的践行、思考与展望
  17. 志愿者服务团队组织由哪些组织组成
  18. 【转】2023年Java学习路线图-黑马程序员
  19. 【国产加密算法-java实现SM3】
  20. bookshelf app android,bookshelf app安卓

热门文章

  1. sd卡格式化不了怎么办?
  2. 闲谈swi与ucos-续篇
  3. Spring源码版本命名规则
  4. 欢迎 收听 海口DJ江林 混音 你的样子 异域风格 为您倾心打造 DJ 江林 reim 短指键盘松哥原创
  5. 1000道软件测试面试题(附答案)百本电子书
  6. 【BOOST C++ 10 时间数据】(4)时间格式输入和输出(11-12)
  7. 一般人学python要多久,新手学python需要多久
  8. Python练级打怪全攻略——从上手到走出新手村
  9. 基于spaCy实现pytextrank对英文短语抽取
  10. 开发常用图标png、ico 图标下载