プロジェクトオイラー問329


Susan は素数カエルを飼っている.
このカエルは, 1 から 500 までの番号がつけられた 500 個の正方形の上を跳びまわる. 左右のいずれかの正方形に等確率で跳ぶことができ, 範囲 [1;500] の外に跳ぶことはできない.
(いずれかの端に着地したなら, 次は自動的に移動可能な正方形に跳ぶ. )
素数である数が書かれた正方形にいる場合, 次の正方形に跳ぶ直前に, カエルは 2/3 の確率で 'P' (PRIME) と鳴き, 1/3 の確率で 'N' (NOT PRIME) と鳴く.
素数でない数が書かれた正方形にいる場合, 次の正方形に跳ぶ直前に, カエルは 1/3 の確率で 'P' と鳴き, 2/3 の確率で 'N' と鳴く.
カエルの開始位置は全ての正方形に対し等確率でランダムであり, また最初の 15 回の鳴き声を聞いたとすると, PPPPNNPPPNPPNPN と聞こえる確率は何か.
約分済みの分数 p/q の形で答えを入力せよ.


両端はそれ以外のマスの2倍として、漸化式で度数分布を数えて比率を計算するだけです。
計算時間数十秒。


#include<stdio.h>
#include<map>
#include<iostream>
const int LIMIT=500;
bool isPrime[LIMIT+1];
__int64 gcd( __int64 a, __int64 b )
{
 __int64 c;
 while ( a != 0 ) {
    c = a; a = b%a;  b = c;
  }
  return b;
}

void set_prime(){
	isPrime[1]=false;
	for(int n=2;n<=LIMIT;n++){
		bool isP=true;
		for(int i=2;i*i<=n;i++){
			if(n%i==0)isP=false;
		}
		isPrime[n]=isP;
	}
} 


int main(){
 	std::map<int,__int64> memo[LIMIT+1];
	set_prime();
for(int i=1;i<=500;i++){
		memo[i][0]=1;
	}

 	
	for(int i=0;i<14;i++){
		std::map<int,__int64> next[LIMIT+1];
		std::map<int,__int64>::iterator it;
		int addPerm=(1<<i);
		for(int j=1;j<=500;j++){
			for(int k=-1;k<=1;k+=2){
				int p=j+k;
				if(p<1||p>LIMIT)continue;
				for(it=memo[p].begin();it!=memo[p].end();it++){
					int perm=(*it).first;
					__int64 c=(*it).second;
					if(isPrime[p]==true){
 						next[j][perm+addPerm]+=c*2;
						next[j][perm]+=c;
				}else{
 						next[j][perm+addPerm]+=c;
						next[j][perm]+=2*c;
						if(p==1||p==500){
							next[j][perm+addPerm]+=c;
							next[j][perm]+=2*c;
						}
					}
				}
			}
		}
 		for(int j=1;j<=LIMIT;j++){
			memo[j].clear();
			memo[j].insert(next[j].begin(),next[j].end());
		}
	}
	
	int ansSeed[15]={1,1,1,1,0,0,1,1,1,0,1,1,0,1,0};
	int ansPerm=0;
 	for(int i=0;i<15;i++)ansPerm+=(ansSeed[i]<<i);
	__int64 all=0,u=0;
	std::map<int,__int64>::iterator it;
	for(int i=1;i<=500;i++){	
		for(it=memo[i].begin();it!=memo[i].end();it++){
			all+=(*it).second*3;
			if(ansPerm==(*it).first){
				if(isPrime[i]==true){
 					u+=(*it).second;
				}else{
					u+=(*it).second*2;
				}
			}
 		}
	}
	__int64 d=gcd(u,all);
	std::cout<<"\n"<<d<<" ans="<<u/d<<"/"<<all/d<<"\n";
}
最終更新:2015年11月12日 13:57