我们可以知道异或可以看成不进位的加法,那么我们就可以得到 \(a + b = a\) ^ \(b + ((a \& b) << 1)\),不难发现 \(\frac{v - u}{2}\) 就是 \(a \& b\) 也就是 \(a, b\) 中同时为 \(1\) 的位置,那么只需要满足 \(\frac{v - u}{2} \& u = 0\) 且 \((i - j) \% 2 = 0\)我们就能合理分配 \(a, b\) 的 \(0 / 1\) 使得 \(u, v\) 能够被表示出来。于是我开始从 \(u, v\) 的判定条件入手,枚举 \(u\) 然后可以从最高位往下做一个 \(dp\) 这样就可以做到 \(O(n \log n)\) 但想了很久都没办法继续优化下去了。

当我们陷入死胡同的时候,不妨走出来换一个方向再继续。因为 \(a + b = v \le n\) 因此我们可以直接考虑枚举这样的 \((a, b)\) 来判定哪些 \((u, v)\) 是合法的,于是我们有了这样一个想法,我们能否将问题转化成统计一些合法的 \((a, b)\) 以知道 \((u, v)\) 的数量呢?实际上我们可以考虑一对合法的 \((u, v)\) 可以被那些 \((a, b)\) 表示出来,我们单独考虑 \(u\) 的二进制位,如果这个位置上是 \(1\) 那么就表示 \(a, b\) 在这一位上有一个是 \(1\) 另一个是 \(0\),如果是 \(u\) 在这一位上是 \(0\) 就表示 \((a, b)\) 在这一位上要么都是 \(1\) 要么都是 \(0\),可以发现因为 \(a + b = v\) 是确定的,因此都是 \(1\) 和都是 \(0\) 的位置是确定的,那么同一对 \((u, v)\) 能被不同的 \((a, b)\) 表示出来当且仅当 \((a, b)\) 在某一位上一个是 \(1\) 一个是 \(0\),因此我们在统计这样 \((a, b)\) 时可以钦定 \(a\) 的每一位都不大于 \(b\),这样就能不重不漏地统计完所有答案了。

于是原问题被我们转化为,统计二元组 \((a, b)\) 的数量满足 \(0 \le a \le b \le n, a + b \le n\) 且在二进制位下 \(a\) 的每一位都不大于 \(b\)。于是我们可以考虑令 \(dp_i\) 表示 \(a + b \le i\) 的合法二元组数量,因为要满足二进制位下 \(a\) 的每一位不大于 \(b\),因此我们在考虑往 \(a, b\) 末尾同时加入一个数时只可能是 \((0, 0) / (0, 1) / (1, 1)\),对应着转移就是 \(dp_i = dp_{\lfloor \frac{i}{2} \rfloor} + dp_{\lfloor \frac{i - 1}{2} \rfloor} + dp_{\lfloor \frac{i - 2}{2} \rfloor}\)。可以用记忆化搜索实现这个过程,可以发现每次往下递归时要求的 \(dp\) 值实际上只有两个,如果 \(i = 2k + 1\) 且 \(k\) 为奇数时我们恰好发现下面需要求的 \(dp\) 值又只有一边,如果 \(k\) 为偶数可以发现最多经过 \(\log n\) 次就会变成 \(k\) 为奇数的情况,而每次除了 \(\frac{k}{2}\) 的部分最多往下多算两次,而最开始 \(i = 2k\) 时与这里类似,因此我们有效的合法状态大约是 \(O(3 \log n)\) 的,实际上效率非常高,有效状态在 \(O(2 \log n) \sim O(3 \log n)\) 之间。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define Mod 1000000007
#define rep(i, l, r) for(int i = l; i <= r; ++i)
int n, cnt;
unordered_map <int, int> dp;
int read(){
char c; int x = 0, f = 1;
c = getchar();
while(c > '9' || c < '0'){ if(c == '-') f = -1; c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
int Inc(int a, int b){
return (a += b) >= Mod ? a - Mod : a;
}
int dfs(int n){
if(dp[n]) return dp[n];
return dp[n] = Inc(Inc(dfs(n / 2), dfs((n - 1) / 2)), dfs((n - 2) / 2));
}
signed main(){
n = read(), dp[0] = 1, dp[1] = 2;
printf("%lld\n", dfs(n));
return 0;
}

可以发现因为是递推式,其实我们可以打表看出规律,但这个递推式有点刁钻,也可能是我太弱了吧。以后这种二进制下满足某种条件的数的个数递推式可以考虑在 \(\lfloor \frac{i}{2} \rfloor\) 附近的值考虑。

AT2272 [ARC066B] Xor Sum的更多相关文章

  1. AT2272 [ARC066B] Xor Sum 题解

    题目连接:传送门 分析 这道题只看题目中给的样例是找不出规律的 所以我们可以打一下表 1, 2, 4, 5, 8, 10, 13, 14, 18 如果你还是没有看出什么规律的话,我们可以从OEIS上搜 ...

  2. HDU 4825 Xor Sum(经典01字典树+贪心)

    Xor Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others) Total ...

  3. 字典树-百度之星-Xor Sum

    Xor Sum Problem Description Zeus 和 Prometheus 做了一个游戏,Prometheus 给 Zeus 一个集合,集合中包括了N个正整数,随后 Prometheu ...

  4. HDU 4825 Xor Sum 字典树+位运算

    点击打开链接 Xor Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others) ...

  5. 2014百度之星第三题Xor Sum(字典树+异或运算)

    Xor Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others) Total ...

  6. Xor Sum 01字典树 hdu4825

    Xor Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others)Total S ...

  7. hdu 4825 Xor Sum (01 Trie)

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=4825 题面: Xor Sum Time Limit: 2000/1000 MS (Java/Others) ...

  8. HDU--4825 Xor Sum (字典树)

    题目链接:HDU--4825 Xor Sum mmp sb字典树因为数组开的不够大一直wa 不是报的 re!!! 找了一下午bug 草 把每个数转化成二进制存字典树里面 然后尽量取与x这个位置上不相同 ...

  9. hdu 4825 Xor Sum trie树

    Xor Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others) Proble ...

随机推荐

  1. MySQL 中的各种锁机制

    行级锁 行级锁是Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁. 行级锁能大大减少数据库操作的冲突.其加锁粒度最小,但加锁的开销也最大.行级锁分为共享锁和排他锁. 特点 开销大,加锁 ...

  2. 向setup.py里添加自定义command

    向setup.py里添加自定义command 参考这里 继承distutils.cmd.Command类: class CCleanCommand(distutils.cmd.Command): &q ...

  3. Java程序设计基础笔记 • 【第5章 循环结构】

    全部章节   >>>> 本章目录 5.1 while循环结构 5.1.1 循环简介 5.1.2 while循环 5.1.3 while循环的使用 5.1.4 while循环的注 ...

  4. http协议的状态码400,401,403,404,500,502,503,301,302等常见网页错误代码

    1xx(临时响应)表示临时响应并需要请求者继续执行操作的状态码. 100(继续) 请求者应当继续提出请求.服务器返回此代码表示已收到请求的第一部分,正在等待其余部分. 101(切换协议) 请求者已要求 ...

  5. Ranger-Kylin插件安装

    Ranger-Kylin插件安装, 从Ranger1.1.0版本开始支持Ranger Kylin插件, 从Kylin2.3.0版本开始支持Ranger Kylin插件的权限控制. 1.获取安装包 sc ...

  6. 如何用微信小程序,每天给自己赚个鸡腿?

    假期如果实在无聊的话,那跟随田同学的脚步上架一个小程序吧. 话说:谁不想拥有一个自己的小程序呢?既可以赚点小钱又可以长长见识. 不懂小程序的小白能不能做出来呢?那来对了,这个教程就是针对小白的. 今天 ...

  7. win10 安装vue 详解-包括node.js、npm、webpack

    1.下载 去官网下载 node.js https://nodejs.org/en/download/ 一般不会选择最新的,我安装的是 12.18.4 进入历史记录页面网址 https://nodejs ...

  8. 关于 vim 的插件 snipmate 以及它的安装方式(使用国内源)

    snipmate 是一个类似代码补全的东西,更好的地方在于自定义补全的内容. 最新的 snipmate 是在 https://github.com/garbas/vim-snipmate 而不是在官网 ...

  9. js 对 date 和 字符串 类型的正确互换【各浏览器兼容】,解决invalid Date

    1.前言 有个需求,想要把指定日期时间的字符串转换成date类型 pc浏览器正常转换,但手机浏览器 返回结果是 invalid Date [无效的日期] 2.原因 出现这样不兼容的原因其实很简单, p ...

  10. centos7 date时间命令

    date "+%F %T" %F     full date; same as %Y-%m-%d  --相当于年月日格式 %T     time; same as %H:%M:%S ...