标签:str coder 返回值 不能 ref 这一 长度 amp 依次
给定\(n\)个整数,依次为\(a_1,a_2,...,a_n。\)
求\(\sum_{i=1}^n\sum_{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),要重新写一个。
#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;
}
标签:str coder 返回值 不能 ref 这一 长度 amp 依次
原文地址:https://www.cnblogs.com/streamazure/p/12585153.html