zoukankan      html  css  js  c++  java
  • xmu 1254.异或求和

    1254.异或求和
    Time Limit: 1000 MS         Memory Limit: 65536 K
    Total Submissions: 52 (19 users)         Accepted: 13 (7 users)

     

    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

    //这题是我无意间看到的、不会做,然后也没找到题解,就把题目发到 ACMDIY群面
    //然后晚上群里一位上海交大的童鞋给了我思路
    //就是把每个数看成二进制数 求区间里面 第k位1有几个
    比如 区间 【1,8】 那么 区间里面第一位是1的有4个 第二位 是1的4个 第3位是1个是4个 第4位是1的有1个
    (只要把这8个数写成二进制,就可以看出来)
    当时我也想过这样、问题是我求不来区间里面这些数中有几个第k位是1
    然后他告诉我 符合 x mod 2^k >=2^(k-1) 的 x 第k位就是1
    这样只要求出 x某个范围 ,其它就是它的等价类了

    这样就可以很快求出 区间【1,N】里面 第k位是1个数 (1<=k<=31)
    那么区间【A,B】里面第k位是1的个数就有了
    然后 就是怎么求和了

    求和比较简单 就是 :
    (区间【A,B】第k位为1的个数乘以区间【C,D】第k位为0的个数+区间【A,B】第k位为0的个数乘以区间【C,D】第k位为1的个数)*2^(k-1)

    #include <iostream> #include <map> #include <stdio.h> #include <math.h> #include <string.h> #include <stdlib.h> #include <algorithm> using namespace std; #define __int64 long long struct node { __int64 rc[32][2]; }; void get1(__int64 n,node *R) { int i; __int64 t=4,p=2; R->rc[1][1]=n/2; if(n%2) R->rc[1][1]++; for(i=2;p<=n;t=(t<<1)) { R->rc[i][1]=(n/t)*(t-p); if(n%t>=p) R->rc[i][1]+=(n%t-p+1); i++; p=(p<<1); } } int main() { node a,b,c,d; int A,B,C,D; int Mod,T; scanf("%d",&T); while(T--) { scanf("%d %d %d %d %d",&A,&B,&C,&D,&Mod); memset(a.rc,0,sizeof(a.rc)); memset(b.rc,0,sizeof(b.rc)); memset(c.rc,0,sizeof(c.rc)); memset(d.rc,0,sizeof(d.rc)); get1(A-1,&a); get1(B,&b); int i; for(i=1;i<=31;i++) a.rc[i][1]=b.rc[i][1]-a.rc[i][1]; __int64 len=(B-A+1); for(i=1;i<=31;i++) a.rc[i][0]=len-a.rc[i][1]; get1(C-1,&c); get1(D,&d); for(i=1;i<=31;i++) c.rc[i][1]=d.rc[i][1]-c.rc[i][1]; len=(D-C+1); for(i=1;i<=31;i++) c.rc[i][0]=len-c.rc[i][1]; __int64 sum=0,m=1; for(i=1;i<=31;i++) { sum=(sum+(m<<(i-1))%Mod*(a.rc[i][0]%Mod*c.rc[i][1]%Mod+a.rc[i][1]%Mod*c.rc[i][0]%Mod)%Mod)%Mod; } Mod=(int)sum; printf("%d\n",Mod); } return 0; }
  • 相关阅读:
    Oracle11g聚合函数
    和为S的连续正数数列,动态规划,C++
    统计一个数组在排序数组中出现的次数,C++,二分查找
    寻找两个链表的第一个公共子节点,C++
    二维数组中的查找
    数组中的逆序对,C++,分治算法
    得到从小到大的第N个丑数的三种方式(C++)一维动态规划
    连续字数组的最大和(Java)一个int数组,求其中的最大的连续数的和
    n个整数,求这中间最小的k个整数(Java)
    两个字符串的最长公共子串求法(C++、动态规划)
  • 原文地址:https://www.cnblogs.com/372465774y/p/2734012.html
Copyright © 2011-2022 走看看