给定A,B,C和D,我们需要在约束x≤A,y≤B下找到三元组(x,y,z)的数量,使得((x x或y)或z)≤D, z≤C其中A,B,C和D各自可达10 ^ 18。
由于答案可能非常大,我们需要输出模数为10 ^ 9 + 7的三元组数。
基本且效率低下的方法:
i=0,j=0,k=0,ans=0
FOR (i<=A)
FOR(j<=B)
FOR(k<=C)
if(((i^j)|k)<=D) ans=ans+1
print ans%1000000007
显然效率非常低,可以采取更好的方式吗?
答案 0 :(得分:0)
这是一个开始的想法。选一个数字r。如果i ^ j = r,并且给出了i,j的可能值是多少?提示:只有一个。
如果只有0≤i≤A的条件,那么很容易找到i ^ j = r的解的个数。现在有两个条件,0≤i≤A和0≤j≤B。这有点困难。发布解决方案,然后我们继续。
解决这个小问题需要将执行时间从O(n ^ 3)降低到O(n ^ 2),这使得有可能求解A,B,C,D≤10^ 6这是不可能的你的算法。
答案 1 :(得分:0)
我们可以通过将数字(x,y,z)分成比特来解决问题。因为x,y,z <= 10 ^ 18,所以每个数字小于 50位。
所以从第一位开始到第50位,我们需要知道四件事
x
是否小于A y
是否小于B z
是否小于C (x ^ y) | z
是否小于D 所以,我们有我们的功能:
long totalNumber(int bit, boolean lessThanA, boolean lessThanB, boolean lessThanC, boolean lessThanD)
对于每个位位置,我们只需要为每个数字x,y,z尝试位0和位1
long result = 0;
for(int x = 0; x < 2; x++){
for(int y = 0; y < 2; y++){
for(int z = 0; z < 2; z++){
//update lessThanA, lessThanB, lessThanC, lessThanD. This step is omitted.
result += totalNumber(bit + 1, lessThanA, lessThanB, lessThanC, lessThanD);
result %= MOD; //remember to take modulo of the result.
}
}
}
对于我们的基本情况,如果我们达到第50位,则返回1
if(bit == 50)
return 1;
因此,在这种情况下应用动态编程,我们有一个表
dp[bit][lessThanA][lessThanB][lessThanC][lessThanD]
并且时间复杂度将降低到O(bit * lessThanA * lessThanB *lessThanC * lessThanD)
,即O(50*2^4) = O(800)
最后注意事项:今天的编程竞赛中经常会出现这种类型的问题。举一个例子,看看problem B round 1B Google Code Jam 2014。
答案 2 :(得分:0)
由于问题涉及逐位操作,让我们考虑二进制示例:
x = ???????????????????
y = ???????????????????
z = ???????????????????
D = 1100000011001101010 (binary)
假设我们可以创建一个方法(可能是组合),将其称为f(D)
,以计算可以合并比特的方式以准确地产生D
。这是考虑低于D
的数字的一种方法:
(1) Any number without the highest bit D has set:
_xxxxxxxxxxxxxxxxxx
(2) Any number with the highest bit D has set, but without the next highest bit D has set:
10xxxxxxxxxxxxxxxxx
(3) Any number with the highest bit and the next highest bit D has set, but without the
third highest bit D has set:
110000000xxxxxxxxxx
And so on...
(1),(2),(3)等中的每一个都是用于组合计算可能的三元组的独特机会,其中可以使用我们先前的方法计算产生已经填充的比特的方式, f
,x
可以轻松计算为所有可能的组合。