kmjp's blog

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

yukicoder : No.2158 X日後に全完するhibit君

ややこしくはあるけど、難しくはない。
https://yukicoder.me/problems/no/2158

問題

Nグループの問題セットからなるコンテストを解くことを考える。
i番目のグループはP[i]問からなり、各問題初見ではS[i]分、2回目以降はT[i]分で解ける。

これからコンテストを繰り返し行う。
各コンテストでは、各グループから1問ずつ問題を等確率ランダムで選び、N問のコンテストを構成する。
ただし、各グループ直前K回で使った問題は使わないこととする。

N問を計60分で解き切ればそこで終了とする。
終了に至るまでのコンテスト回数の最小値・最大値・期待値を求めよ。

解法

各グループのうち解いたことのある問題数を状態として、DPであと何回コンテスト参加すれば解き切れるか、最小値・最大値・期待値を計算しよう。

以下のコードではN重ループを書いている。
Nごとにコードを書くのは面倒なので、Nが最大値でない場合、S[i]=T[i]=0である問題セットを追加し、Nが常に最大値になるようにしている。

int N,K;
int P[55],S[55],T[55];
double dp[3][6][6][6][6][6][6];
int V[6];

void solve() {
	int i,j,k,l,r,x,y; string s;
	
	cin>>N>>K;
	FOR(i,N) cin>>P[i]>>S[i]>>T[i];
	for(i=N;i<6;i++) P[i]=5;
	
	int sum=0;
	FOR(i,6) sum+=T[i];
	if(sum>60) {
		cout<<-1<<endl;
		return;
	}
	sum=0;
	FOR(i,6) sum+=S[i];
	if(sum<=60) {
		cout<<"1 1 1"<<endl;
		return;
	}
	
	for(V[0]=P[0];V[0]>=K;V[0]--)
	for(V[1]=P[1];V[1]>=K;V[1]--)
	for(V[2]=P[2];V[2]>=K;V[2]--)
	for(V[3]=P[3];V[3]>=K;V[3]--)
	for(V[4]=P[4];V[4]>=K;V[4]--)
	for(V[5]=P[5];V[5]>=K;V[5]--) {
		int mask;
		dp[0][V[0]][V[1]][V[2]][V[3]][V[4]][V[5]]=1e9;
		dp[1][V[0]][V[1]][V[2]][V[3]][V[4]][V[5]]=-1e9;
		dp[2][V[0]][V[1]][V[2]][V[3]][V[4]][V[5]]=0;
		int V2[6];
		
		FOR(mask,64) {
			double p=1;
			int sum=0;
			FOR(i,6) {
				if(mask&(1<<i)) { //new
					p=p*(P[i]-V[i])/(P[i]-K);
					sum+=S[i];
					V2[i]=V[i]+1;
				}
				else {
					p=p*(V[i]-K)/(P[i]-K);
					sum+=T[i];
					V2[i]=V[i];
				}
			}
			if(p==0) continue;
			if(sum<=60) {
				dp[0][V[0]][V[1]][V[2]][V[3]][V[4]][V[5]]=1;
				chmax(dp[1][V[0]][V[1]][V[2]][V[3]][V[4]][V[5]],1.0);
				dp[2][V[0]][V[1]][V[2]][V[3]][V[4]][V[5]]+=p;
			}
			else {
				chmin(dp[0][V[0]][V[1]][V[2]][V[3]][V[4]][V[5]],dp[0][V2[0]][V2[1]][V2[2]][V2[3]][V2[4]][V2[5]]+1);
				chmax(dp[1][V[0]][V[1]][V[2]][V[3]][V[4]][V[5]],dp[1][V2[0]][V2[1]][V2[2]][V2[3]][V2[4]][V2[5]]+1);
				dp[2][V[0]][V[1]][V[2]][V[3]][V[4]][V[5]]+=p*(dp[2][V2[0]][V2[1]][V2[2]][V2[3]][V2[4]][V2[5]]+1);
			}
		}
	}
	
	_P("%.12lf %.12lf %.12lf\n",dp[0][K][K][K][K][K][K]+K,dp[1][K][K][K][K][K][K]+K,dp[2][K][K][K][K][K][K]+K);
	
}

まとめ

★3.5位に感じた。