zz: http://www.strongczq.com/2012/03/srm537-div1-2-kingxmagicspells.html
题目原文:http://community.topcoder.com/stat?c=problem_statement&pm=11822
题目原文:http://community.topcoder.com/stat?c=problem_statement&pm=11822
题目大意:
有N个编号为0,1,...,N-1的房间,每个房间里有若干只鸭子,鸭子数量用int[] ducks来表示。每一天会以等概率事件发生以下两件事之一:
- 事件一:对于每一个房间i,鸭子数ducks[i]与数组int[] s1的对应元素s1[i]做异或位运算并重新赋值给ducks[i];
- 事件二:对于每一个房间i,该房间中的所有鸭子转移到数组int[] s2所表示的对应元素s2[i]编号房间中,s2数组中的所有元素各不相同,并且所有房间的鸭子转移是在瞬间完成的。
问:第K天之后房间0中鸭子数的期望值是多少?
数据规模:N和K均为[1,50],ducks[]、s1[]、s2[]中的元素的取值范围为[0, 1,000,000,000]
思路:
鸭子数只存在两种变化方式:
- 与一个整数做异或位操作
- 不同房间鸭子数互换
这两种变化方式存在一个特点,如果把鸭子数表示成二进制形式,那么二进制中的不同位是可以相互独立进行考虑的。这一点是解题的关键,因为这样就可以分别计算每一位在K天之后的期望值,然后得到综合值。
由于二进制位只可能取0或1两个值,因此我们可以模拟每一天过后,每个房间的鸭子数中该位取0和1的概率分别是多少。K天之后0房间内累加鸭子数每一位的期望值乘以该二进制位代表的值,即为最终的鸭子数期望值。
Java代码:
public class KingXMagicSpells {
public double expectedNumber(int[] ducks, int[] spellOne, int[] spellTwo, int K) {
double res = 0.0;
for (int i = 0; i < 31; ++i) {
int[] sBit = new int[spellOne.length];
double[][] p = new double[ducks.length][2];
for (int j = 0; j < ducks.length; ++j) {
sBit[j] = (spellOne[j] >> i) & 1;
p[j][(ducks[j] >> i) & 1] = 1.0;
}
for(int k = 0; k < K; ++k){
double[][] np= new double[ducks.length][2];
for(int j = 0; j < ducks.length; ++j){
np[j][0 ^ sBit[j]] += 0.5 * p[j][0];
np[j][1 ^ sBit[j]] += 0.5 * p[j][1];
np[spellTwo[j]][0] += 0.5 * p[j][0];
np[spellTwo[j]][1] += 0.5 * p[j][1];
}
p = np;
}
res += p[0][1] * (1 << i);
}
return res;
}
}