【每日一题】补档 AGC015D A or...or B Problem | 构造 | 困难

2023-10-07 05:28

本文主要是介绍【每日一题】补档 AGC015D A or...or B Problem | 构造 | 困难,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目内容

原题链接

给定一个区间 [ A , B ] [A,B] [A,B] ,从中选出两个数 x x x y y y x x x 可以等于 y y y ,问 x x x y y y 的结果可以得到多少个不同的数。

数据范围

  • 0 ≤ A ≤ B < 2 60 0\leq A\leq B<2^{60} 0AB<260

题解

如果 A = B A=B A=B,那么答案就是 1 1 1 。特判即可。

对于 [ A , B ] [A,B] [A,B] 中的数, A A A B B B 的二进制表示前缀中相同的部分或运算后的值必然是确定的,所以这部分可以不用考虑了。

举个例子: A = 13 = 110 0 2 , B = 15 = 111 1 2 A=13=1100_2,B=15=1111_2 A=13=11002,B=15=11112,两者二进制都是以 11 11 11 开头的,这部分就是确定的,故这部分可以不用考虑了。

可以将其重新设置为 A = 0 0 2 , B = 1 1 2 A=00_2,B=11_2 A=002,B=112

B > A B>A B>A ,故两者从高位到低位的第一个不同的二进制数位 k k k k k k 必然是最高位。

那么我们可以把可选择的数 x x x y y y 分为三部分,其中 x ≥ y x\geq y xy

  • 选择 x k = 0 , y k = 0 x_k=0,y_k=0 xk=0,yk=0,取值范围为: [ A , 2 k − 1 ] [A, 2^k-1] [A,2k1]
  • 选择 x k = 1 , y k = 0 x_k=1,y_k=0 xk=1,yk=0,取值范围为: [ 2 k + A , 2 k + 1 − 1 ] [2^k+A, 2^{k+1}-1] [2k+A,2k+11]
  • 选择 x k = 1 , y k = 1 x_k=1,y_k=1 xk=1,yk=1,取值范围为: [ 2 k , 2 k + 2 s + 1 − 1 ] [2^k, 2^k+2^{s+1}-1] [2k,2k+2s+11] ,其中 s s s 为从高位到低位第二个为 1 1 1 的二进制位,当不存在时, s = − 1 s=-1 s=1

对于 x k = 0 , y k = 0 x_k=0,y_k=0 xk=0,yk=0,由于取值最小值为 A A A ,取值最大值为 2 k − 1 2^k-1 2k1 ,故或运算的值必然在这个范围内。
具体构造出值 v ∈ [ A , 2 k − 1 ] v\in[A, 2^k-1] v[A,2k1],令 x = y = v x=y=v x=y=v 即可。

对于 x k = 1 , y k = 0 x_k=1,y_k=0 xk=1,yk=0,第 k k k 位或运算结果为 1 1 1 ,那么只需要考虑低 k − 1 k-1 k1 位。因为 y ≥ A y\geq A yA ,所以或运算的结果必然 ≥ A \geq A A ,但是低 k − 1 k-1 k1 位至多是全部为 1 1 1 ,即 2 k − 1 2^k-1 2k1
具体构造出值 v ∈ [ 2 k + A , 2 k + 1 − 1 ] v\in[2^k+A, 2^{k+1}-1] v[2k+A,2k+11],令 x = 2 k , y = v − 2 k x=2^k,y=v-2^k x=2k,y=v2k 即可。

对于 x k = 1 , y k = 1 x_k=1,y_k=1 xk=1,yk=1,如果 B = 2 k B=2^k B=2k ,那么只能选择一个数。
否则 B > 2 k B>2^k B>2k s s s 为从高位到低位第二个为 1 1 1 的二进制位。

对于 b i t ∈ ( s , k ) bit\in(s,k) bit(s,k) 的二进制位 b i t bit bit ,这些必然不可能为 1 1 1
那么 v k , v k − 1 , ⋯ , v s + 1 v_k,v_{k-1},\cdots,v_{s+1} vk,vk1,,vs+1 这些二进制位都已确定。那么可以构造出 [ 2 k , 2 k + 2 s + 1 − 1 ] [2^k, 2^k+2^{s+1}-1] [2k,2k+2s+11]
具体构造出值 v ∈ [ 2 k , 2 k + 2 s + 1 − 1 ] v\in[2^k, 2^{k}+2^{s+1}-1] v[2k,2k+2s+11]

  • v < 2 k + 2 s + 1 − 1 v<2^{k}+2^{s+1}-1 v<2k+2s+11 x = v , y = 2 k x=v,y=2^k x=v,y=2k
  • v = 2 k + 2 s + 1 − 1 v=2^{k}+2^{s+1}-1 v=2k+2s+11 x = 2 k + 2 s , y = 2 k + 2 s − 1 x=2^k+2^{s},y=2^k+2^{s}-1 x=2k+2s,y=2k+2s1

当然,这里的 x k = 1 , y k = 0 x_k=1,y_k=0 xk=1,yk=0 x k = 1 , y k = 1 x_k=1,y_k=1 xk=1,yk=1 的取值区间可能会有交集。

因为 2 k < 2 k + A 2^k<2^k+A 2k<2k+A ,所以必然是 2 k + 2 s + 1 − 1 ≥ 2 k + A 2^{k}+2^{s+1}-1\geq 2^k+A 2k+2s+112k+A ,即 2 s + 1 − 1 ≥ A 2^{s+1}-1\geq A 2s+11A ,即 2 s + 1 > A 2^{s+1}>A 2s+1>A ,此时 A A A 的二进制为 1 1 1 的最高位小于等于 B B B 的二进制为 1 1 1 的次高位。

时间复杂度: O ( log ⁡ max ⁡ ( A , B ) ) O(\log \max(A,B)) O(logmax(A,B)) ,至多 60 60 60

代码

#include <bits/stdc++.h>
using namespace std;typedef long long ll;int main()
{ios::sync_with_stdio(false);cin.tie(nullptr);ll A, B;cin >> A >> B;if (A == B) {cout << "1\n";return 0;}vector<int> vecA(60), vecB(60);for (int i = 0; i < 60; ++i) {vecA[i] = A % 2;vecB[i] = B % 2;A /= 2;B /= 2;}while (!vecA.empty() && vecA.back() == vecB.back()) {vecA.pop_back();vecB.pop_back();}int n = int(vecA.size());reverse(vecA.begin(), vecA.end());reverse(vecB.begin(), vecB.end());int s = -1;for (int i = 1; i < vecB.size(); ++i) {if (vecB[i] == 1) {s = n - 1 - i;break;}}ll ans = 0;A = 0;for (int i = 0; i < vecA.size(); ++i) A = A * 2 + vecA[i];ll R = (1ll << (n - 1)) + (1ll << (s + 1)) - 1;ll L = A;if (R >= (1ll << (n - 1)) + A) {R = (1ll << n) - 1;ans = R - L + 1;} else {ans = R - L + 1;ans += (1ll << (n - 1)) - 1 - A + 1;}cout << ans << "\n";return 0;
}

这篇关于【每日一题】补档 AGC015D A or...or B Problem | 构造 | 困难的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/156305

相关文章

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

uva 10025 The ? 1 ? 2 ? ... ? n = k problem(数学)

题意是    ?  1  ?  2  ?  ...  ?  n = k 式子中给k,? 处可以填 + 也可以填 - ,问最小满足条件的n。 e.g k = 12  - 1 + 2 + 3 + 4 + 5 + 6 - 7 = 12 with n = 7。 先给证明,令 S(n) = 1 + 2 + 3 + 4 + 5 + .... + n 暴搜n,搜出当 S(n) >=

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟)

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟) 题目描述 给定一个链表,链表中的每个节点代表一个整数。链表中的整数由 0 分隔开,表示不同的区间。链表的开始和结束节点的值都为 0。任务是将每两个相邻的 0 之间的所有节点合并成一个节点,新节点的值为原区间内所有节点值的和。合并后,需要移除所有的 0,并返回修改后的链表头节点。 思路分析 初始化:创建一个虚拟头节点

leetcode105 从前序与中序遍历序列构造二叉树

根据一棵树的前序遍历与中序遍历构造二叉树。 注意: 你可以假设树中没有重复的元素。 例如,给出 前序遍历 preorder = [3,9,20,15,7]中序遍历 inorder = [9,3,15,20,7] 返回如下的二叉树: 3/ \9 20/ \15 7   class Solution {public TreeNode buildTree(int[] pr

每日一题|牛客竞赛|四舍五入|字符串+贪心+模拟

每日一题|四舍五入 四舍五入 心有猛虎,细嗅蔷薇。你好朋友,这里是锅巴的C\C++学习笔记,常言道,不积跬步无以至千里,希望有朝一日我们积累的滴水可以击穿顽石。 四舍五入 题目: 牛牛发明了一种新的四舍五入应用于整数,对个位四舍五入,规则如下 12345->12350 12399->12400 输入描述: 输入一个整数n(0<=n<=109 ) 输出描述: 输出一个整数

每日一练7:简写单词(含链接)

1.链接 简写单词_牛客题霸_牛客网 2.题目 3.代码1(错误经验) #include <iostream>#include <string>using namespace std;int main() {string s;string ret;int count = 0;while(cin >> s)for(auto a : s){if(count == 0){if( a <=

【每日刷题】Day113

【每日刷题】Day113 🥕个人主页:开敲🍉 🔥所属专栏:每日刷题🍍 🌼文章目录🌼 1. 91. 解码方法 - 力扣(LeetCode) 2. LCR 098. 不同路径 - 力扣(LeetCode) 3. 63. 不同路径 II - 力扣(LeetCode) 1. 91. 解码方法 - 力扣(LeetCode) //思路:动态规划。 cl

C++中类的构造函数调用顺序

当建立一个对象时,首先调用基类的构造函数,然后调用下一个派生类的 构造函数,依次类推,直至到达派生类次数最多的派生次数最多的类的构造函数为止。 简而言之,对象是由“底层向上”开始构造的。因为,构造函数一开始构造时,总是 要调用它的基类的构造函数,然后才开始执行其构造函数体,调用直接基类构造函数时, 如果无专门说明,就调用直接基类的默认构造函数。在对象析构时,其顺序正好相反。

力扣 739. 每日温度【经典单调栈题目】

1. 题目 理解题意: 1.1. 给一个温度集合, 要返回一个对应长度的结果集合, 这个结果集合里面的元素 i 是 当前 i 位置的元素的下一个更高温度的元素的位置和当前 i 位置的距离之差, 若是当前元素不存在下一个更高温度的元素, 则这个位置用0代替; 2. 思路 本题用单调栈来求解;单调栈就适用于来求当前元素左边或者右边第一个比当前元素大或者小的元素;【单调栈:让栈中的元素保持单调

每日一题——第八十一题

打印如下图案: #include<stdio.h>int main() {int i, j;char ch = 'A';for (i = 1; i < 5; i++, ch++){for (j = 0; j < 5 - i; j++){printf(" ");//控制空格输出}for (j = 1; j < 2 * i; j++)//条件j < 2 * i{printf("%c", ch