给定n(n <= 1000000)个正整数(每个数小于1000000)。任务是计算给定数字的所有不同组合的按位xor(^ c / c ++)值的总和。
时限是1秒。 例如,如果给出3个整数为7,3和5,则答案应为7 ^ 3 + 7 ^ 5 + 3 ^ 5 = 12.
我的方法是:
#include <bits/stdc++.h>
using namespace std;
int num[1000001];
int main()
{
int n, i, sum, j;
scanf("%d", &n);
sum=0;
for(i=0;i<n;i++)
scanf("%d", &num[i]);
for(i=0;i<n-1;i++)
{
for(j=i+1;j<n;j++)
{
sum+=(num[i]^num[j]);
}
}
printf("%d\n", sum);
return 0;
}
但我的代码未能在1秒内运行。如何以更快的方式编写代码,可以在1秒内运行?
编辑:实际上这是一个在线评判问题,我的上述代码超出了Cpu限制。
答案 0 :(得分:1)
你需要计算大约1e12 xors才能暴力破解。现代处理器每秒可以执行大约1e10个这样的操作。所以蛮力无法奏效;因此他们正在寻找你找出更好的算法。
因此,您需要找到一种方法来确定答案,而无需计算所有这些xors。
提示:如果所有输入数字都是零或一(一位),你能想到一种方法吗?然后将其扩展为两位,三位,等等?
答案 1 :(得分:0)
此函数以二次方式增长(感谢@rici)。大约25,000个正整数,每个为999,999(最差情况),单独的for循环计算可以在大约一秒钟内完成。尝试使用您指定的输入和100万个正整数使这个工作似乎不可能。
答案 2 :(得分:0)
优化代码时,您可以选择3种不同的路径:
很可能有一种更快速的数学方法来测量每对组合然后将它们相加,但我知道不是。在任何情况下,在现代处理器上,你最多只需要削减微秒;那是因为你正在做基本操作(xor和sum)。
优化架构也没什么意义。它通常在重复分支中变得很重要,你在这里没有这样的东西。
算法中最大的问题是从标准输入读取。尽管&#34; scanf
&#34;在您的计算机代码中只需要5个字符,在机器语言中这是您程序的主要部分。不幸的是,如果每次运行代码时数据都会实际发生变化,那么就无法满足从stdin读取的要求,无论您使用scanf
,std::cin >>
还是偶数,都没有区别将尝试实现您自己的方法从输入中读取字符并将其转换为整数。
所有这些都假定你不希望人类在不到一秒的时间内输入数千个数字。我想您可以通过以下方式运行代码:myprogram < data
。
答案 3 :(得分:0)
使用Alan Stokes's answer中的提示,您可能具有线性复杂度而不是二次方,具体如下:
std::size_t xor_sum(const std::vector<std::uint32_t>& v)
{
std::size_t res = 0;
for (std::size_t b = 0; b != 32; ++b) {
const std::size_t count_0 =
std::count_if(v.begin(), v.end(),
[b](std::uint32_t n) { return (n >> b) & 0x01; });
const std::size_t count_1 = v.size() - count_0;
res += count_0 * count_1 << b;
}
return res;
}
说明:
x^y = Sum_b((x&b)^(y&b))
其中b
是单位掩码(从1<<0
到1<<32
)。count_0
和count_1
相应的位数设置为0
或1
,我们有count_0 * (count_0 - 1)
0^0
,count_0 * count_1
0^1
和count_1 * (count_1 - 1)
1^1
(以及0^0
和1^1
为0
)。