kmjp's blog

競技プログラミング参加記です

yukicoder : No.1501 酔歩

こういう式変形さっとできないなぁ。
https://yukicoder.me/problems/no/1501

問題

N個のマスが並んでおり、各マスiには数値A[i]が書かれている。
今、駒がK番目のマスにある。
この駒は以下のように動く。

  • 駒が1番かN番のマスに到達したら終了。
  • そうでない場合、現在位置iに対し、A[i-1]/(A[i-1]+A[i+1])の確率で(i-1)番に、残りの確率で(i+1)番に動く。

最終的にコマがN番のマスに到達して終了する確率を求めよ。

解法

f(i) := i番目のマスに駒があるとき、最後N番のマスに到達して終了する確率
とすると、f(K)を求める問題となる。このf(i)は以下のようになる。

  • f(1)=0
  • f(N)=1
  • f(i) = (A[i-1]*f(i-1)+A[i+1]*f(i+1))/(f(i-1)+f(i+1))

この式を頑張って変形すると、
 \displaystyle f(i)=\frac{\sum_{j=1}^{i-1}\frac{1}{A_jA_{j+1}}}{\sum_{j=1}^{N-1}\frac{1}{A_jA_{j+1}}}

となるので、1/(A[i]*A[i+1])の累積和を取れば容易に計算できる。
この問題は有理数で答えるので、1~10の2値の積の最大公約数である6350400を使い、分子分母ともに6350400/(A[i]*A[i+1])を用いるようにすると小数を使わずに済む。

int N,K;
int A[101010];

void solve() {
	int i,j,k,l,r,x,y; string s;
	
	cin>>N>>K;
	FOR(i,N) cin>>A[i+1];
	if(K==N) {
		cout<<1<<"/"<<1<<endl;
	}
	else if(K==1) {
		cout<<0<<endl;
	}
	else {
		ll p=0,q=0;
		for(i=1;i<K;i++) (p+=6350400/(A[i]*A[i+1]));
		for(i=1;i<N;i++) (q+=6350400/(A[i]*A[i+1]));
		ll g=__gcd(p,q);
		cout<<p/g<<"/"<<q/g<<endl;
		
	}
	
}

まとめ

両端の確率がわかっているケース、割かし苦手。