我在TopCoder解决方案中遇到了这段代码让我很困惑。有一个正偶数和奇数整数的数组列表。我认为它返回的总和是偶数模MOD的子集数。我相信MOD只是为了避免溢出,如果列表很大,所以如果你保持数字小于32,那么我认为你不需要它。
ArrayList l = { ... positive even and odd integers ... };
int dp[] = {1,0};
for (int i = 0; i < l.size(); ++i) {
int even = dp[0];
int odd = dp[1];
if (l.get(i) % 2 == 0) {
even *= 2;
odd *= 2;
} else {
even += odd;
odd = even;
}
dp[0] = even % MOD;
dp[1] = odd % MOD;
}
return (dp[0] - 1 + MOD) % MOD;
如果所有整数都是偶数,那么我认为答案是2 ^ N-1。 但似乎至少有一个奇数,答案变为2 ^(N-1)-1。是对的吗?如果是这样,为什么要跟踪偶数/奇数?
答案 0 :(得分:4)
这根本不需要迭代程序。假设你的集合有N个元素,k even和N-k odd。那么,k偶数并不是真正相关的;它们的2 ^ k个组合中的任何一个,以及具有偶数和的奇数的子集,组合成偶数和。
奇数的组合有多少甚至总和?如果N-k> 0,它们有2 ^(N - k - 1)。所以,你是对的。这是一个编码问题而不是数学问题。
但是给定的算法如下:
当N = 0时,集合中只有一个子集:空集合,总和为0.因此,从even=1
和odd=0
开始。现在归纳步骤:假设前k个元素的分区数是even
和odd
。
如果第k + 1个数是偶数,则其和为偶数的第一个k的任何子集可以附加(或不附加)第k + 1个元素,使偶数子集的数量加倍。这同样适用于具有奇数和的子集。
如果第k + 1个数是奇数,那么其和为偶数的前k个数的任何子集都不会给出具有第k + 1个数的任何新的偶数子集,而第一个k的一个子集如果附加第k + 1个,则和为奇数的数字给出一个具有偶数和的数字。因此,新even
是旧even
和odd
的总和。同样,新的odd
也是相同的总和,因此新的odd
等于新的even
。
注意所有k的even + odd == 2^k
,无论如何。并且,一旦有一个奇数,该指数even == odd
并且全部更高。