Let's ignore the sample case by subtracting one from T (at the end, we'll add one back to the answer). Then the probability of Bessie's solution solving exactly i test cases out of T is precisely pi=(Ti)2T.
Define Ex to be the expected value given at most x submissions, where E0=0. The goal is to compute EK. If we have already computed Ex then Ex+1 may be computed as follows:
In equations,
Subtask 1: The above equations can be simulated in O(TK) time.
The solution below uses Python's decimal module for increased precision (though it was not necessary to do so).
from decimal import * getcontext().prec = 100 T, K = map(int, input().split()) T -= 1 prob = [Decimal(1)] for _ in range(T): prob = [(x+y)/2 for x, y in zip([Decimal(0)]+prob, prob+[Decimal(0)])] E = Decimal(T)/2 K -= 1 while K > 0: K -= 1 next_E = 0 for i in range(T+1): next_E += prob[i]*max(i,E) E = next_E getcontext().prec = 20 print(E+1)
Subtask 2: Let a=∑⌊Ex⌋i=0pi and b=∑Ti=⌊Ex⌋+1ipi, such that Ex+1=aEx+b. Observe that when ⌊Ex+1⌋=⌊Ex⌋, we do not need to recalculate a and b.
The runtime of the solution below is O(T2+K).
T, K = map(int, input().split()) T -= 1 prob = [1] for _ in range(T): prob = [(x+y)/2 for x, y in zip([0]+prob, prob+[0])] E = T/2 K -= 1 for f in range(T): a, b = 0, 0 for i in range(T+1): if i <= f: a += prob[i] else: b += prob[i]*i while K > 0 and E < f+1: E = a*E+b K -= 1 print(E+1)
Full Credit: For a solution without a factor of O(K), we need to be able to advance x multiple submissions forward at once.
Under this assumption, we can write
by the geometric series formula. It remains to either determine that ⌊EK⌋=⌊Ex⌋, or find the smallest q≤K−x such that ⌊Ex+q⌋>⌊Ex⌋.
After finding q via one of the two methods below, we may simulate min(q,K−x) submissions at once and then update x+=min(q,K−x). If we now have x=K, then we're done. Otherwise, we know that ⌊Ex⌋ has increased by one. ⌊Ex⌋ can increase a total of at most T times, which is a lot smaller than K.
Method 1: Binary search on q.
My code follows. The total number of calls to pow is O(TlogK).
from decimal import * getcontext().prec = 100 T, K = map(int, input().split()) T -= 1 prob = [Decimal(1)] for _ in range(T): prob = [(x+y)/2 for x, y in zip([Decimal(0)]+prob, prob+[Decimal(0)])] E = Decimal(T)/2 K -= 1 for f in range(T): if K == 0: break if E // 1 > f: continue a, b = Decimal(0), Decimal(0) for i in range(T+1): if i <= f: a += prob[i] else: b += prob[i]*i def next_E(q): # value of E after q timesteps return pow(a,q)*E+(1-pow(a,q))/(1-a)*b # binary search on q q_lo = 1 while 2*q_lo <= K and next_E(q_lo*2) < f+1: q_lo *= 2 q_hi = 2*q_lo while q_lo < q_hi: q_mid = (q_lo+q_hi)//2 if next_E(q_mid) < f+1: q_lo = q_mid+1 else: q_hi = q_mid # advance q submissions q_lo = min(q_lo, K) K -= q_lo E = next_E(q_lo) getcontext().prec = 20 print(E+1)
Method 2: We can rewrite ⌊Ex+q⌋>⌊Ex⌋ as follows:
Then we can take the natural logarithm of both sides to get
The runtime of the solution below is O(T2). a corresponds to probabilityLower and b1−a corresponds to expectedHigher.
Danny Mittal's code:
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.StringTokenizer; public class CowCamp { public static void main(String[] args) throws IOException { BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); StringTokenizer tokenizer = new StringTokenizer(in.readLine()); int t = Integer.parseInt(tokenizer.nextToken()) - 1; int k = Integer.parseInt(tokenizer.nextToken()); double[][] probability = new double[t + 1][t + 1]; probability[0][0] = 1.0; for (int a = 1; a <= t; a++) { probability[a][0] = probability[a - 1][0] / 2.0; for (int b = 1; b <= t; b++) { probability[a][b] = (probability[a - 1][b - 1] + probability[a - 1][b]) / 2.0; } } double expected = .0; int attempts = 0; for (int score = 1; score <= t; score++) { double probabilityLower = .0; for (int lower = 0; lower < score; lower++) { probabilityLower += probability[t][lower]; } double expectedHigher = .0; for (int higher = score; higher <= t; higher++) { expectedHigher += probability[t][higher] * ((double) higher); } expectedHigher /= 1.0 - probabilityLower; double difference = expectedHigher - expected; double differenceToAchieve = expectedHigher - ((double) score); double attemptsNeeded = Math.log(differenceToAchieve / difference) / Math.log(probabilityLower); boolean doneHere = attemptsNeeded > k - attempts; int attemptsToUse = doneHere ? (k - attempts) : (int) Math.round(Math.ceil(attemptsNeeded)); difference *= Math.pow(probabilityLower, attemptsToUse); expected = expectedHigher - difference; attempts += attemptsToUse; if (attempts == k) { break; } } System.out.println(1.0 + expected); } }