zoukankan      html  css  js  c++  java
  • 【位运算】大吉大利

    大吉大利

    给定(n)个整数,依次为(a_1,a_2,...,a_n。)

    (sum_{i=1}^nsum_{j=1}^n(a_i&a_j))(&)是二进制的与运算符

    容易想到二重循环

    for(int i=1;i<=n;i++)
    	for(int j=1;j<=n;j++)
    		ans+=(a[i]&a[j]);
    

    时间复杂度为(O(n^2)),又(n<=10^5),超时了。

    考虑与运算的性质:是将每个数字转化成二进制数,再一位一位作计算的。只有当两个数都为1时结果才为1,其它情况结果均为0。

    以样例为例,5个数字化为二进制数得到

    (00001)

    (00010)

    (00011)

    (00100)

    (00101)

    对于最右边一列,在(a[1])与其它数(包括它本身)进行与运算时,这一列所得结果之和为3。(a[3])(a[5])时的情况同理。故这一列在求和过程中的总结果为9。即这一列中1的数目的平方。

    根据上述规律,继续计算其它列,最终得到的一串数字即所求和的二进制表示。

    注意,将所求和的二进制数转化为十进制时,因为返回值可能需要long long储存,所以不能用math.h里的pow函数(返回类型为double),要重新写一个。

    $color{green}{查看代码}$
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<math.h>
    using namespace std;
    
    long long a[1005], ans = 0;
    long long pow(int base, int n)
    {
        long long sum=1;
        while (n)
        {
            if (n&1) sum = base*sum;
            base *= base;
            n >>= 1;
        }
        return sum;
    }
    
    int main() {
        long long n, maxc = 0;
        cin >> n;
        for (int i = 1;i <= n;i++) {
            long long num, cnt = 0, nm;
            cin >> num;
            while (num) {//数num的二进制数中有几位是1
                if (num & 1) a[cnt]++;
                //num&1不为0,说明num的二进制数中的最右边那位是1
                //a[cnt]++表示计数第cnt列的1的个数
                cnt++;
                num >>= 1;
                //相当于num/=2
                //num二进制数右移1位
            }
            maxc = max(maxc, cnt);
            //更新最长的二进制数的长度 
        }
        for (int i = 0;i < maxc;i++)
            ans += a[i] * a[i] * pow(2, i);
        cout << ans;
        return 0;
    }
    
  • 相关阅读:
    Product of Array Except Self
    Sliding Window Maximum
    First Bad Version
    Perfect Squares
    IPsec Note
    BGP实验第9-10选路原则
    BGP选路第3条原则
    BGP选路原则第1条至第8条
    BGP选路原则笔记 Cyrus
    Lab Block hole of BGP
  • 原文地址:https://www.cnblogs.com/streamazure/p/12585153.html
Copyright © 2011-2022 走看看