ABC050D/ARC066D Xor Sum
题目大意
可表为 $(a \xor b, a + b)$ 的二元组有多少个?
$a, b$ 满足下列约束条件:
① $a, b$ 是非负整数;
② $a + b \le N$,$N$ 是给定的正整数且 $N \le 10^{18}$ 。
我的思考
考虑 $a \xor b$ 的二进制表示,对其进行数位 DP。
问题转化成
$ 0 \le x < 2^k $
$ 0 \le y < 2^k $
$ x + y \le M$
$k, M$ 给定且 $ 2^k \le M < 2^{k + 1}$ 。
二元组 $(x \xor y, x + y)$ 有多少种不同取值?
这个问题并不容易,思路至此中断。
参考题解
https://blog.csdn.net/just_sort/article/details/54288233
Key observation
可以给 $a, b$ 增加一个约束而不改变原题目的解:
③ $a$ 的每个二进制位都不大于 $b$ 的对应二进制位。
在这三条约束下,可以证明 $(a, b) \mapsto (a \xor b, a + b)$ 是单射。
证明:设 $(a_1, b_1) \ne (a_2, b_2)$ 。若 $a_1 \xor b_1 = a_2 \xor b_2$ 则必有某个二进制位,在此位上某一组的值是 $(0,0)$,另一组的值是 $(1, 1)$ 。考虑满足此条件的最高位,易见 $a_1+ b_1 \ne a_2 + b_2$ 。证毕。
至此问题化为在上述三个约束下,满足 $a + b \le N$ 的二元组 $(a, b)$ 有多少个?
解法一(DP,top-down with memoization)
令 $f(N)$ 表示所求,考虑 $a, b$ 的最低位(即权重为 $2^0$ 的位),$a, b$ 在此位上的取值有三种情况:$(0, 0)$、$(0, 1)$、$(1, 1)$;得到递推
$$ f(N) = f(N / 2) + f((N - 1) / 2) + f( (N - 2) / 2) $$
边界条件:
$ f(0) = 1, f(1) = 2 $
问题:算出 $f(N)$ 需要计算多少个状态?
据说状态数在 $(\log N)^2$ 的级别,我不能证明。
解法二(DP)
DP 状态
dp[i][ j ][k]:$a, b$ 的后 $i$ 位已经确定,$a + b$ 的后 $i$ 位和 $N$ 的后 $i$ 位的大小关系是 $j$(j = 0 代表小于,j = 1 代表等于,j = 2 代表大于),$k$ 表示 $a$ 的后 $i$ 位和 $b$ 的后 $i$ 位相加是否会向第 $i + 1$ 位产生进位(k = 0, 1)。
转移方式
对于状态 dp[i][ j ][k],枚举 $a, b$ 在第 $i + 1$ 位上的取值,转移到状态 dp[i+1][ j' ][k' ]。
$N$ 的二进制第 $i + 1$ 位是 0
dp[i][ j ][0] -- (0, 0) --> dp[i+1][ j ][0]
dp[i][ j ][0] -- (0, 1) --> dp[i+1][2][0]
dp[i][ j ][0] -- (1, 1) --> dp[i+1][ j ][1]
dp[i][ j ][1] -- (0, 0) --> dp[i+1][2][0]
dp[i][ j][1] -- (0, 1) --> dp[i+1][ j][1]
dp[i][ j][1] -- (1, 1) --> dp[i+1][ 2][1]
$N$ 的二进制第 $i + 1$ 位是 1
dp[i][ j][0] -- (0, 0) --> dp[i+1][0][0]
dp[i][ j][0] -- (0, 1) --> dp[i+1][ j][0]
dp[i][ j][0] -- (1, 1) --> dp[i+1][0][1]
dp[i][ j][1] -- (0, 0) --> dp[i+1][ j][0]
dp[i][ j][1] -- (0, 1) --> dp[i+1][0][1]
dp[i][ j][1] -- (1, 1) --> dp[i+1][ j][1]
代码
https://atcoder.jp/contests/abc050/submissions/8191466
DP 状态优化
上述 dp 数组的第二维可以优化。以 j = 0 表示小于等于,j = 1 表示大于;或者以 j = 0 表示小于等于,j = 1 表示不计大小关系(即小于、等于、大于三种情况之和)。 按前一种定义,dp[i][j][k] 的转移方式为
$N$ 的二进制第 $i + 1$ 位是 0
dp[i][ j ][0] -- (0, 0) --> dp[i+1][ j ][0]
dp[i][ j ][0] -- (0, 1) --> dp[i+1][1][0]
dp[i][ j ][0] -- (1, 1) --> dp[i+1][ j ][1]
dp[i][ j ][1] -- (0, 0) --> dp[i+1][1][0]
dp[i][ j][1] -- (0, 1) --> dp[i+1][ j][1]
dp[i][ j][1] -- (1, 1) --> dp[i+1][1][1]
$N$ 的二进制第 $i + 1$ 位是 1
dp[i][ j][0] -- (0, 0) --> dp[i+1][0][0]
dp[i][ j][0] -- (0, 1) --> dp[i+1][ j][0]
dp[i][ j][0] -- (1, 1) --> dp[i+1][0][1]
dp[i][ j][1] -- (0, 0) --> dp[i+1][ j][0]
dp[i][ j][1] -- (0, 1) --> dp[i+1][0][1]
dp[i][ j][1] -- (1, 1) --> dp[i+1][ j][1]
参考代码
https://atcoder.jp/contests/abc050/submissions/8192354
按后一种定义,dp[i][j][k] 的转移方式为
$N$ 的二进制第 $i + 1$ 位是 0
dp[i][ j ][0] -- (0, 0) --> dp[i+1][ j ][0]
dp[i][1][0] -- (0, 1) --> dp[i+1][1][0]
dp[i][ j][0] -- (1, 1) --> dp[i+1][ j ][1]
dp[i][1][1] -- (0, 0) --> dp[i+1][1][0]
dp[i][ j][1] -- (0, 1) --> dp[i+1][ j][1]
dp[i][1][1] -- (1, 1) --> dp[i+1][1][1]
$N$ 的二进制第 $i + 1$ 位是 1
dp[i][1][0] -- (0, 0) --> dp[i+1][0][0]
dp[i][1][0] -- (1, 1) --> dp[i+1][0][1]
dp[i][ j][0] -- (0, 1) --> dp[i+1][ j][0]
dp[i][ j][1] -- (0, 0) --> dp[i+1][ j][0]
dp[i][ j][1] -- (1, 1) --> dp[i+1][ j][1]
dp[i][1][1] -- (0, 1) --> dp[i+1][0][1]
这种状态定义的好处是转移路径少,坏处是状态转移过程容易写错。
另一种 DP
仍按上述思路,下面介绍官方题解给出的 DP 方法。这种方法的复杂度比较清楚,并且其思想可以用于求解更为一般的数位 DP 问题。
DP 状态
dp[i][ j ]:$a + b$ 的二进制表示的第 $i$ 位及以上的部分(确切地说,权值大于等于 $2^{i}$ 的那些位)已经确定且不考虑第 $i$ 位以下部分,$a + b$ 的二进制第 $i$ 位及以上的部分(换言之,$a + b$ 已经确定的部分)与 $N$ 的二进制第 $i$ 位及以上的部分的差是 $j$(亦即 (N >> i) - ((a + b) >> i) == j)的情况有多少种。
举例言之,N = 10101。a + b = 1****(符号 * 表示暂不考虑这些位上的值)属于状态 dp[4][0],1 - 1 = 0;a + b = 0**** 属于状态 dp[4][1],1 - 0 = 1;a + b = 00*** 属于状态 dp[3][2],10 - 00 = 2;a + b = 10*** 属于状态 dp[3][0],10 - 10 = 0;a + b = 100** 属于状态 dp[2][1],101 - 100 = 1;000** 属于状态 dp[2][5],101 - 000 = 5。
对于状态 dp[i][ j ],注意到当 $j \ge 2$ 时,$a + b$ 的二进制第 $0$ 到 $i - 1$ 位可以任意选取,共有 $3^{i}$ 种情况。所以 $j \ge 2$ 的状态可以用 $j = 2$ 表示,因此 $j$ 可以只取 $0, 1, 2$ 这三个值。另外,由于只有 $j = 0, 1$ 的状态需要转移,在编程实现时,dp 数组的第二维取 2 即可。
转移方式
只有 dp[i][0] 和 dp[i][1] 需要转移;看 $N$ 的二进制第 $i - 1$ 位上是多少,枚举 $a, b$ 的二进制第 $i - 1$ 位。
(1)$N$ 的二进制第 $i - 1$ 位上是 0
dp[i][0] -- (0, 0) --> dp[i - 1][0]
dp[i][1] -- (0, 0) --> dp[i - 1][2]
dp[i][1] -- (0, 1) --> dp[i - 1][1]
dp[i][1] -- (1, 1) --> dp[i - 1][0]
(2)$N$ 的二进制第 $i - 1$ 位上是 1
dp[i][0] -- (0, 0) --> dp[i - 1][1]
dp[i][0] -- (0, 1) --> dp[i - 1][0]
dp[i][1] -- (0, 0) --> dp[i - 1][2]
dp[i][1] -- (0, 1) --> dp[i - 1][2]
dp[i][1] -- (1, 1) --> dp[i - 1][1]
边界条件
由于 $N \le 10^{18}$ 而 $\log 10^{18} \approx 59.79$,故边界条件可取为 dp[60][0] = 1, dp[60][1] = 0 。
复杂度
时间复杂度 $O(\log N)$,空间复杂度 $O(\log N)$ 。
代码
https://atcoder.jp/contests/arc066/submissions/8186588
References
https://qiita.com/259_Momone/items/86e90d17e4efe3b22433
ABC050D/ARC066D Xor Sum的更多相关文章
- HDU 4825 Xor Sum(经典01字典树+贪心)
Xor Sum Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 132768/132768 K (Java/Others) Total ...
- 字典树-百度之星-Xor Sum
Xor Sum Problem Description Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包括了N个正整数,随后 Prometheu ...
- HDU 4825 Xor Sum 字典树+位运算
点击打开链接 Xor Sum Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 132768/132768 K (Java/Others) ...
- 2014百度之星第三题Xor Sum(字典树+异或运算)
Xor Sum Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 132768/132768 K (Java/Others) Total ...
- Xor Sum 01字典树 hdu4825
Xor Sum Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 132768/132768 K (Java/Others)Total S ...
- hdu 4825 Xor Sum (01 Trie)
链接:http://acm.hdu.edu.cn/showproblem.php?pid=4825 题面: Xor Sum Time Limit: 2000/1000 MS (Java/Others) ...
- HDU--4825 Xor Sum (字典树)
题目链接:HDU--4825 Xor Sum mmp sb字典树因为数组开的不够大一直wa 不是报的 re!!! 找了一下午bug 草 把每个数转化成二进制存字典树里面 然后尽量取与x这个位置上不相同 ...
- hdu 4825 Xor Sum trie树
Xor Sum Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 132768/132768 K (Java/Others) Proble ...
- hdu 4825 Xor Sum(trie+贪心)
hdu 4825 Xor Sum(trie+贪心) 刚刚补了前天的CF的D题再做这题感觉轻松了许多.简直一个模子啊...跑树上异或x最大值.贪心地让某位的值与x对应位的值不同即可. #include ...
随机推荐
- 2019牛客暑期多校训练营(第一场)H 线性基+计算贡献
题意 给n个整数,求满足子集异或和为0的子集大小之和. 分析 将问题转化为求每个元素的贡献次数之和. 先对n个数求线性基,设线性基大小为r,即插入线性基的数字个数为r,可以分别计算线性基内数的贡献和线 ...
- JIRA备份,数据迁移以及小问题
Jira的备份(切记将许可证号备份) Jira默认会打开自动备份的功能,备份路径为/var/atlassian/application-data/jira/export 管理员账号登录Jira,点击右 ...
- 三、Reids(高性能)key-value服务器知识整合
一.Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库. 知识链接:https://www.runoob.com/redis/redis-backup.html ht ...
- Java工程师成神之路(2018年最新版)
一.基础篇 JVM JVM内存结构 堆.栈.方法区.直接内存.堆和栈区别 Java内存模型 内存可见性.重排序.顺序一致性.volatile.锁.final 垃圾回收 内存分配策略.垃圾收集器(G1) ...
- better-scroll 的介绍
配置项中的 probeType 属性,是number,当值为 0 ,不会实时监听 scroll 事件,设置为 2 - 3 ,可以实时监听 scroll 事件 pullUpload 选项,设置为 fal ...
- omniplan
汉化版安装包 下载链接:https://pan.baidu.com/s/104ZddPtNWTHyEMZx90agKw 密码:qizl 序列号 Name: Appked Serial: I ...
- mysql使用命令行执行存储过程
编写存储过程sql 以给brand表添加phone字段为例: DROP PROCEDURE IF EXISTS UpdateColum; CREATE PROCEDURE UpdateColum() ...
- Python中列表操作进阶及元组
列表高级操作 一.遍历列表 >>> ls=['a','d','it'] >>> for val in ls: ... print (val) ... a d it ...
- 校验表单demo
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 深入学习重点分析java基础---第一章:深入理解jvm(java虚拟机) 第一节 java内存模型及gc策略
身为一个java程序员如果只会使用而不知原理称其为初级java程序员,知晓原理而升中级.融会贯通则为高级 作为有一个有技术追求的人,应当利用业余时间及零碎时间了解原理 近期在看深入理解java虚拟机 ...