TopCoder SRM 338 Div1 Medium RandomSwaps
問題
n枚のカードがある。
これらのカードに対して、2枚のカードをランダムに選び、その位置を交換するという操作をswapCount回行う。
操作前にa番目にあったカードが操作後にb番目にある確率を求めよ。
制約条件
n≦1000
swapCount≦100000
方針
最初にa番目にあったカードが、i回の操作の後でb番目に来ている確率をp[i]とすると、
p[i+1]=(n-2)/n * p[i] + 2/(n*(n-1)) * (1-p[i])の漸化式が成り立つので、
これをswapCountまでまわせばよい。
swapCountが10億くらいまでだと思っていたので行列を使って計算した。
ソースコード
typedef vector<vd> mat; mat operator*(mat a,mat b){ mat res(2,vd(2)); rep(i,2)rep(j,2)rep(k,2)res[i][j]+=a[i][k]*b[k][j]; return res; } mat pow(mat m,int n){ mat res(2,vd(2)); res[0][0]=res[1][1]=1; for(;n;n/=2){ if(n&1)res=res*m; m=m*m; } return res; } class RandomSwaps { public: double getProbability(int n, int c, int a, int b) { if(n==2){ return (a==b)^(c%2)?1:0; } mat m(2,vd(2)); m[0][0]=(n-1.0)*(n-2)/(n*(n-1.0)); m[0][1]=2.0/(n*(n-1.0)); m[1][0]=2.0*(n-1)/(n*(n-1.0)); m[1][1]=1-m[0][1]; m=pow(m,c); mat t(2,vd(1)); if(a==b)t[0][0]=1; else t[1][0]=1; m=m*t; return m[0][0]; } };