AT2272 [ARC066B] Xor Sum
我们可以知道异或可以看成不进位的加法,那么我们就可以得到 \(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的更多相关文章
- AT2272 [ARC066B] Xor Sum 题解
题目连接:传送门 分析 这道题只看题目中给的样例是找不出规律的 所以我们可以打一下表 1, 2, 4, 5, 8, 10, 13, 14, 18 如果你还是没有看出什么规律的话,我们可以从OEIS上搜 ...
- 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 ...
随机推荐
- 一个老菜鸟的年度回忆 & 智能工厂奋斗的第三年,可能有你值得借鉴的
岁月蹉跎,寒冬的夜晚仍伏案疾书,见论坛中有诸多大神已经开始了一年的总结,突然安奈不住心中的躁动,也想为这今年的奋斗留下只言片语,没有年初的目标总结,没有未来的展望,就想作为一篇日记记录今年项目精力,为 ...
- [opencv]建立纯色图
1.建立纯白图片,指定大小 250*250为图片的宽高,可自己设置. Mat white = cv::Mat(250,250,CV_8UC3,Scalar(255,255,255)); 2.建立纯黑图 ...
- Capstone CS5268DEMOBOARD原理图|TYPEC转HDMI+VGA+PD3.0+USB3.0扩展坞方案
Capstone CS5268DEMOBOARD原理图|TYPEC转HDMI+VGA+PD3.0+USB3.0四合一设计参考 CS5268 是typec转HDMI+VGA+pd3.0+U3四合一拓展坞 ...
- <数据结构>XDOJ317.输出完全二叉树的某一层
问题与解答 问题描述 对一棵完全二叉树,输出某一深度的所有节点,有则输出这些节点,无则输出EMPTY. 输入格式 输入有多组数据. 每组数据第一行输入一个结点数n(1<=n<=1000), ...
- C语言string操作
创建方式 字符数组:空间已定 字符指针:未分配空间 初始化 字符数组: 创建与赋值必须在同一行 指定大小:未填满部分用'\0'填充 用字符串初始化:末尾自动添加'\0' 不初始化赋值则乱值 字符指针: ...
- 初识python: 字符编码转换
指定当前文件编码格式:#-*- coding:utf-8 -*-unicode(万国码): 英文字母 1个字节,中文3个字节python中所有的字符都是unicode编码所有非unicode编码互转都 ...
- 详谈 Java工厂 --- 静态工厂 【简单工厂模式】
1.前言 什么是工厂模式? 就是为了尽可能将代码的耦合度降低而产生的设计模式. 这篇随笔讲解静态工厂的思路和具体操作. 2.总结 (1)静态工厂又称 简单 工厂模式 ,是最最简单的工厂模式. (2)优 ...
- window10 查看端口列表 - 查看占用的进程-销毁该进程
cmd进入指令框后 查看端口列表 netstat -ano 查看占用的进程 [6666是端口号对应的进程数] tasklist|findstr "6666" 销毁该进程 [6666 ...
- Java中Jar包调用命令行运行编译
原文链接:https://www.toutiao.com/i6491877373942694413/ 记事本编写两个简单的类 文件结构目录 启动DOS,进入文件所在目录 进入到class所在文件的目录 ...
- 【golang学习记录】环境搭建
[golang学习记录]环境搭建 一. 概述 本文是[golang学习记录]系列文章的第一篇,安装Go语言及搭建Go语言开发环境,接下来将详细记录自己学习 go 语言的过程,一方面是为了巩固自己学到的 ...