位运算 - 异或求和

2024-09-05 17:08
文章标签 运算 求和 异或

本文主要是介绍位运算 - 异或求和,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 异或求和

Problem's Link:  http://acm.xmu.edu.cn/JudgeOnline/problem.php?id=1254


 

Mean: 

Description
给你2个区间[A,B]和[C,D],现在只要求你求出区间[A,B]和[C,D]内任意2个整数异或后的和,因为答案可能会很大,你只需将结果%mod即可。
For(i:A→B)
For(j:C→D)
Sum += (i^j);
Input
输入第一行为T(T<=15),表示测试的数据组数,第2行到T+1行,每行5个数字,分别为A,B,C,D,mod.
(1<=A,B,C,D<2^31,A<=B,C<=D,1<=mod& lt;=1,000,000,007),即为上述的数值。 Output 输出有T行,每行有一个数字,代表题述的答案(即Sum % mod)。 Sample Input 3 5 11 9 12 43 9 12 5 11 83 1 1 2 2 3 Sample Output 18 24 0

 

analyse:

看到这么大的输入,再看看时限是500ms,开始有点摸不着头脑,看来只能用log(n)的方法来做了。

典型的位运算题目。

首先我们求出[A,B]区间中所有数各个位上1的个数。比如[1~8]就是1,4,4,4;

怎么求呢?

我们可以打表找一下规律:

1: 0001

2: 0010

3: 0011

4: 0100

5: 0101

6: 0110

7: 0111

8: 1000

9: 1001

.....

我们会发现,[1,n]中第k位总共1的个数就是:n/(k<<1) *(k<<1 /2 )。或者说:符合 x mod 2^k >=2^(k-1) 的 x 第k位就是1。

额,这个要自己去找规律。

要求[A~B]区间内各位上1的个数,只需要B1[i]-A1[i]就行。

同理,我们可以求出[C~D]区间上各位1的个数。

剩下的就是怎么求和了。

求和比较简单:

区间【A,B】第k位为1的个数乘以区间【C,D】第k位为0的个数+区间【A,B】第k位为0的个数乘以区间【C,D】第k位为1的个数)*2^(k-1)。

 

Time complexity: O(logn)

 

Source code: 

/*
* this code is made by crazyacking
* Verdict: Accepted
* Submission Date: 2015-08-05-11.38
* Time: 0MS
* Memory: 137KB
*/
#include <queue>
#include <cstdio>
#include <set>
#include <string>
#include <stack>
#include <cmath>
#include <climits>
#include <map>
#include <cstdlib>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#define  LL long long
#define  ULL unsigned long long
using namespace std;

void get1( LL n , LL arr []) { /**< 求1~n所有数各个位上1的个数之和 */
      for( int i = 1; i < 32; ++ i) arr [ i ] = 0;
      for( LL i = 1 , f = 2 ,b = 1; b <=n; ++ i , f <<= 1 ,b <<= 1) {
            arr [ i ] =(n / f) *( f / 2); /**< 对于每一位,1~n可分为n/t组(t是每组的01数量),其中每组有t/2个是1 */
            if(n % f >=b) arr [ i ] +=(n % f -b + 1); /**< 加上余数部分 */
      }
}

int main() {
      ios_base :: sync_with_stdio( false);
      cin . tie( 0);
      LL n , t;
      cin >> t;
      while( t --) {
            LL A ,B , C , D , Mod , a1 [ 32 ], b1 [ 32 ], c1 [ 32 ], d1 [ 32 ];
            cin >> A >>B >> C >> D >> Mod;
            get1( A - 1 , a1); get1(B , b1); get1( C - 1 , c1); get1( D , d1);
            LL ab1 [ 32 ], ab0 [ 32 ], cd1 [ 32 ], cd0 [ 32 ];
            for( int i = 1; i < 32; ++ i) ab1 [ i ] = b1 [ i ] - a1 [ i ], cd1 [ i ] = d1 [ i ] - c1 [ i ];
            int l1 =B - A + 1 , l2 = D - C + 1;
            for( int i = 1; i < 32; ++ i) ab0 [ i ] = l1 - ab1 [ i ], cd0 [ i ] = l2 - cd1 [ i ];
            LL sum = 0 , base = 1;
            for( int i = 1; i < 32; ++ i)
                  sum =( sum +( base <<( i - 1)) % Mod *( ab0 [ i ] % Mod * cd1 [ i ] % Mod + ab1 [ i ] % Mod * cd0 [ i ] % Mod) % Mod) % Mod;
            cout << sum << endl;
      }
      return 0;
}
/*

*/

 

这篇关于位运算 - 异或求和的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

uva 575 Skew Binary(位运算)

求第一个以(2^(k+1)-1)为进制的数。 数据不大,可以直接搞。 代码: #include <stdio.h>#include <string.h>const int maxn = 100 + 5;int main(){char num[maxn];while (scanf("%s", num) == 1){if (num[0] == '0')break;int len =

【Java中的位运算和逻辑运算详解及其区别】

Java中的位运算和逻辑运算详解及其区别 在 Java 编程中,位运算和逻辑运算是常见的两种操作类型。位运算用于操作整数的二进制位,而逻辑运算则是处理布尔值 (boolean) 的运算。本文将详细讲解这两种运算及其主要区别,并给出相应示例。 应用场景了解 位运算和逻辑运算的设计初衷源自计算机底层硬件和逻辑运算的需求,它们分别针对不同的处理对象和场景。以下是它们设计的初始目的简介:

位运算:带带孩子吧,孩子很强的!

快速进制 在聊到位运算之前,不妨先简单过一遍二进制的东西。熟悉二进制和十进制的快速转换确实是掌握位运算的基础,因为位运算直接在二进制位上进行操作。如果不熟悉二进制表示,很难直观理解位运算的效果。 这里主要涉及二进制和十进制之间的互相转换。 十进制转二进制 十进制转二进制可以使用常见的 除2取余法 进行。每次将十进制除以2并记录所得余数,直到商为0,然后再将记录的余数 从下往上排列即

1 模拟——67. 二进制求和

1 模拟 67. 二进制求和 给你两个二进制字符串 a 和 b ,以二进制字符串的形式返回它们的和。 示例 1:输入:a = "11", b = "1"输出:"100"示例 2:输入:a = "1010", b = "1011"输出:"10101" 算法设计 可以从低位到高位(从后向前)计算,用一个变量carry记录进位,如果有字符没处理完或者有进位,则循环处理。两个字符串对

Leetcode67---二进制求和

https://leetcode.cn/problems/add-binary/description/ 给出的两个二进制,我们可以从最后开始往前运算。 给当前短的一位前面补充0即可。 class Solution {public String addBinary(String a, String b) {//给的就是二进制字符串 最后一位开始遍历 如果没有就补充0?StringBuil

UVa 10820 Send a Table (Farey数列欧拉函数求和)

这里先说一下欧拉函数的求法 先说一下筛选素数的方法 void Get_Prime(){ /*筛选素数法*/for(int i = 0; i < N; i++) vis[i] = 1;vis[0] = vis[1] = 0;for(int i = 2; i * i < N; i++)if(vis[i]){for(int j = i * i; j < N; j += i)vis[j] =

【hdu】敌兵布阵(线段树,更加结点,区间求和)

最近开始刷线段树,主要围绕notonlysuccess的线段树总结刷。 结点修改还是比较简单的,不需要什么懒惰标记,直接二分递归就可以了。 #include <iostream>#include <cstdlib>#include <cstdio>#include <string>#include <cstring>#include <cmath>#include <vecto

快速幂运算的一些模板

这里用递归和循环两种做法来做。 简单来说,快速幂就是把底数扩大,指数缩小,比如2*2=4;计算2的幂时,就可以转换成4的幂来运算,这样可以避免在计算大的数据时爆int的现象  //递归int power(int a,int n){int ans;if(n==2) ans=1;else{ans=power(a*a,n/2);if(n%2==1) ans*=a;}return ans;}

上海市计算机学会竞赛平台2024年7月月赛丙组求和问题

题目描述 给定 nn 个整数 a1,a2,…,ana1​,a2​,…,an​,请问这个序列最长有多少长的前缀,满足元素的和大于或等于 00?如果任何长度大于 00 的前缀之和都为负数,则输出 00 输入格式 第一行:单个整数表示 nn第二行:nn 个整数表示 a1,a2,…,ana1​,a2​,…,an​ 输出格式 单个整数:表示最长的前缀长度,使得前缀的和大于等于 00 数据范围