Overview
Prerequisites: Random functions and Introduction to probability
This article gives a brief classification of randomization techniques related to OI/ICPC and introduces each category. It also introduces some methods that are rarely used in OI/ICPC but are relatively close to OI/ICPC in style and other respects; these are marked with (*) beforehand.
This classification does not represent a broad consensus and certainly cannot cover every possibility, so it is provided for reference only.
Notation and conventions:
- denotes the probability that event occurs.
- denotes the expectation of random variable .
- The assignment symbol introduces a new quantity; for example, introduces a quantity with value , namely .
Covering target elements with random sets
There is one or more solution in a huge solution space that we want. We can try casting a net repeatedly; as long as we catch the target solution once, we succeed.
Example: Testing whether a graph is tripartite
Problem
Given a simple undirected graph with vertices and edges, color every vertex with one of the three colors RGB so that every pair of adjacent vertices has a different color, or report that no solution exists.
For each vertex , independently choose a color from , denoted , and stipulate that is not colored . The probability that an optimal solution happens to satisfy these restrictions is clearly .
Under these restrictions, for a pair of adjacent vertices , the requirement that have different colors is equivalent to the following implication:
- For every color other than , denoted , if is colored , then is colored .
Thus, for each we can set a Boolean variable , whose value indicates which of the two remaining colors is assigned to . The problem can then be solved with a 2-SAT model in time.
This gives a success probability of for one run. Run the algorithm times and output a solution if any run succeeds; this guarantees a success probability of . (See the later section on the analysis of probability bounds for details.)
Review: In this problem, the “solution space” is the set . Each time, we search for the “target solution”—a valid coloring—within a smaller range by imposing random restrictions.
Example: CodeChef SELEDGE
Brief problem statement
Given an undirected graph whose vertices and edges have nonnegative weights, find an edge set of size , denoted , that maximizes the sum of the weights of vertices incident to minus the sum of the weights of edges in . The weight of a vertex is counted only once.
Observation: if three selected edges form a path, deleting the middle edge is never worse; if several selected edges form a cycle, deleting any one of them is never worse.
Corollary: the edge set selected by an optimal solution must form several vertex-disjoint stars (that is, trees of diameter at most two).
Corollary: the edge set selected by an optimal solution must form a bipartite graph.
Independently color every vertex black or white with equal probability, and require this coloring to be exactly the black-and-white coloring of the bipartite graph corresponding to the optimal solution.
Let us calculate the probability that the optimal solution satisfies this requirement:
- Consider a star with vertices. It clearly has two coloring schemes, so the probability that it receives the correct colors is .
- Suppose the numbers of vertices in the stars of the optimal solution are . Then , where is the maximum number of edges that can be selected.
- Therefore, the probability that all stars receive the correct colors is .
Under these restrictions, try to build a min-cost flow model to calculate the optimal answer:
- Build a bipartite graph, with white vertices on the left connected to and black vertices on the right connected to .
- For a white vertex , add an edge from to it with capacity 1 and cost , and an edge with capacity and cost 0.
- For a black vertex , add an edge from it to with capacity 1 and cost , and an edge with capacity and cost 0.
- For an edge in the original graph with white and black, add an edge from to with capacity 1 and cost .
- Restrict the flow in this graph to be at most ; the opposite of the minimum cost is then the answer.
If we solve this with min-cost flow using SPFA, the complexity is . Proof:
- First, the number of SPFA runs is clearly .
- Then, during one SPFA run, any vertex is enqueued at most times. This is because:
- At any moment there are at most edges carrying flow; otherwise, more than edges would have been selected in the original graph.
- For any augmenting path of length , at least edges are reverse edges of some edge carrying flow, because all forward edges point from the left side of the graph to the right side, and only these reverse edges can point from right to left.
- Combining the two facts, the length of any augmenting path is at most .
- Therefore, the complexity is .
As in the previous problem, we need to repeat the entire process times to obtain a success probability of . The total complexity is .
Hitting a target set with random elements
We need to determine an arbitrary element of a set, so we randomly select elements in the hope of hitting this set exactly.
Example: Gym 101550I
Brief problem statement
The graph consists of two parallel chains and two parallel edges connecting the chains. Given several simple paths in this graph, each representing a phone call, choose as few edges as possible on which to place wiretaps so that every given path contains at least one wiretap.
The entire graph can be decomposed into a cycle and four chains extending from the cycle. For any one of these four chains, denoted , a greedy algorithm can easily find a placement of wiretaps on the chain satisfying the following conditions:
- Under the condition that all calls entirely within are intercepted, use the fewest possible wiretaps.
- Under the previous condition, make the minimum distance from the wiretaps on to the cycle as small as possible.
- The purpose of this requirement is to intercept as many calls as possible with exactly one endpoint inside .
Next consider the four edges where the chains meet the cycle. We can brute-force whether to place a wiretap on each of these edges. Clearly, if we want to intercept calls crossing between a chain and the cycle, placing a wiretap on one of these four edges is optimal. We can now divide the call paths into the following types:
- Call paths entirely on a chain. These paths have already been intercepted, so they can be ignored.
- Call paths crossing between a chain and the cycle that have already been intercepted. They can be ignored.
- Call paths crossing between a chain and the cycle that have not been intercepted. We can cut off their chain portions directly (because the wiretap placement on the chains is fixed) and retain only their cycle portions.
- Call paths entirely on the cycle.
The problem has now been reduced to a problem on the cycle.
Suppose the optimal solution places wiretaps on the edge set . If we have identified any element of , say , we can:
- First break the cycle at to form a chain.
- Then start at and proceed greedily, repeatedly finding the next edge on which to place a wiretap. With suitable preprocessing, each greedy step can be performed in time.
- Thus solve the problem in time.
We randomly choose an edge on the cycle, stipulate that , and then perform the process above, repeating it several times and taking the best result.
Analyze the complexity of one run:
- Observation: let denote the optimal solution among all solutions that select . Then .
- Therefore, the complexity of one run is .
Analyze the success probability:
- Clearly, the success probability of one run is , where is the length of the cycle.
- Therefore, we need to repeat the process times to obtain a success probability of .
In conclusion, the complexity of the algorithm is .
Example: CSES 1685 New Flight Routes
Brief problem statement
Given a directed graph, add as few edges as possible to make it strongly connected. You must output a construction.
First condense the original graph into strongly connected components. Our goal is clearly to make every sink reachable from every source.
It is not difficult to prove that we only need to add edges from sinks to sources, because any other added edge can be replaced by an edge from a sink to a source that is no worse.
One core operation is to take a sink and a source (they need not belong to the same weakly connected component), and add an edge to make both and cease to be sinks or sources (call this Goal I). Ideally, each operation reduces the number of sinks and sources by one. We continue until only one sink or only one source remains, which is a trivial case. Thus we conjecture that the answer is the larger of the number of sources and the number of sinks.
It is not difficult to see that the necessary and sufficient condition for the operation above to achieve Goal I is that has a predecessor other than , and has a successor other than . It can be proved (as we will show shortly) that every DAG with at least two sources and at least two sinks contains such an , but this existence result does not help us construct a solution; further analysis is needed.
- Even with this necessary and sufficient condition, it is difficult to obtain an algorithm directly, mainly because adding the edge may affect the validity of other pairs , which is difficult to handle.
We know little about the relationships between sources and sinks (we may not even be able to quickly query whether a pair is reachable without DFS + bitset preprocessing, which the time limit does not allow). This suggests that we need some very general and powerful property.
Observation: pairs that do not satisfy Goal I number at most , where is the number of sources and is the number of sinks.
- Reason: if each such is viewed as an edge joining , all these edges form a graph consisting of several vertex-disjoint paths, so the number of edges is no more than the number of vertices minus one.
- The motivation for this observation is that, to apply an existence result in an algorithm, a qualitative conclusion often first needs to be strengthened into a quantitative one.
Corollary: if is chosen uniformly at random, the probability that it satisfies the preceding requirement is at least .
- Notice that this conclusion is strictly stronger than the existence result given earlier.
Corollary: choose pairs without common elements independently and uniformly at random, and perform the corresponding operations in order (that is, add the edges ). Then the probability that all these operations satisfy Goal I is at least .
- Reason:
After selecting pairs consecutively, it is easy to check whether they all satisfy Goal I: run strongly connected component condensation once more and check whether have both decreased by . If each round reduces , then must become 1 within rounds, reducing the problem to the trivial case.
Algorithm pseudocode
while(n>1 and m>1):
randomly choose k=min(n,m)/2 pairs (s,t)
add edge t->s for all these pairs
if new_n>n-k or new_m>m-k:
roll_back()
solve_trivial()
The complexity is .
Review: We need to determine any pair that can achieve Goal I, so we randomly choose .
Using randomization to obtain properties of random data
If the data of a problem is generated randomly, we may be able to use properties of random data to solve it. In some cases, even if the data is not randomly generated, we can use randomization to give it some characteristics of random data, thereby helping to solve the problem.
Example: Randomized incremental method
A randomly generated sequence of elements may have properties such as a small expected number of changes in the prefix optimum, and the randomized incremental method obtains such properties by randomly shuffling the input sequence.
See randomized incremental method for details.
Example: randomized solution for TopCoder MagicMolecule
Brief problem statement
Given an undirected graph with vertices and vertex weights, among all cliques of size at least , find one with maximum total vertex weight.
A meet-in-the-middle search is natural. Split the vertex set evenly into two halves , both of size . Compute an array giving the maximum total weight of all cliques in the vertex set having size . Then enumerate every clique in the right half, find the vertices in the left half adjacent to every vertex in (call this vertex set ), and update the answer with .
- Notice that an -time transition is possible for every . Specifically, choose an arbitrary element of and consider cases:
- If is not in the optimal clique, transition from .
- If is in the optimal clique, transition from , where denotes the set of neighbors of .
- Do not forget to use to update .
This solution is too slow. Try to optimize it:
- Split the vertex set uniformly at random. Then, with appreciable probability, the vertex set of the optimal solution is also split exactly evenly, namely .
- Of course, may be odd. For simplicity, assume it is even here; the odd case does not fundamentally change the solution.
- Experiments show that about 20 random trials give a high probability of satisfying this property at least once. In other words, if our algorithm relies on being split evenly, repeating the algorithm 20 times and taking the best result likewise gives a high probability of obtaining the correct answer.
- With this property, we can stipulate directly that the left clique and right clique both have size . This improves the complexity in two ways:
- no longer needs to record the size dimension.
- Since we only need to consider cliques of size , the number of left cliques and right cliques to consider is greatly reduced, to about .
- The bottleneck now becomes finding the weight sum of a particular subset on one side, because this requires preprocessing.
- Solution: split in half again. When querying the weight sum of a subset, split that subset into two halves, query each half, and add the answers.
- This is enough to solve the problem.
Review: A random set has the property that the sizes of the two parts into which it is split do not differ too greatly, and we obtain this property by randomly splitting the set.
Randomization for hashing
Example: UOJ #207 Covalent Grandpa Visits Changsha
Brief problem statement
Maintain a dynamically changing tree and a dynamically changing set of vertex pairs. You need to support:
- Delete and add edges, while guaranteeing that the result remains a tree.
- Add or delete a vertex pair.
- Given an edge , determine whether, for every vertex pair in the set, lies on the simple path between .
For every edge in the graph, define as the set of important paths passing through that edge (that is, the pairs in the problem). Consider dynamically maintaining the hash value of each set . Then it is easy to determine whether equals the universal set, that is, whether is an “unavoidable path”.
To hash the sets, assign each a random nonnegative integer less than , denoted . The hash value of a set is the XOR of the values of its elements.
Then the hash value of any fixed set is uniformly distributed over (in other words, the hash value ranges over and every value has the same probability). This is because:
- A single is clearly uniformly distributed.
- The XOR of two independent random variables that are both uniformly distributed over is also uniformly distributed over . This is not difficult to prove.
Thus the correctness probability of the algorithm is guaranteed.
As for maintaining this hash value, an LCT suffices.
Example: CodeChef PANIC and analysis of its error rate
The rough solution to this problem is:
- It can be proved1 that , with respect to , satisfies an -order linear recurrence.
- Use the BM algorithm to find this recurrence.
- Use the recurrence and the Cayley–Hamilton theorem to calculate .
Here we focus only on the second part, namely how to find a recurrence for a sequence of matrices. Thus we only need to consider the following problem:
Problem
Given a sequence of matrices that satisfies a homogeneous linear recurrence modulo (scalar multiplication and addition in the recurrence are defined as matrix scalar multiplication and addition), find the shortest recurrence.
If a sequence of matrices satisfies a recurrence , then each of its entries also satisfies . However, if we find a shortest recurrence for one entry, may be shorter than , causing a problem.
Solution: assign each matrix entry a $ [!note]+ Brief problem statement
Given two directed graphs whose edge labels are lowercase letters, compute for each graph the multiset of strings corresponding to all paths (possibly an infinite multiset), and determine whether the two multisets are equal. If they are not equal, output a shortest string whose occurrence counts in the two multisets differ.
Let denote the hash value of the multiset of all strings corresponding to paths in graph that start at vertex and have length . Consider every state in increasing order of ; when transitioning, enumerate the outgoing edges of and stipulate that the chosen edge is the first edge of the path.
To determine whether a bad string of length exists, it suffices to integrate and compare and separately (the wildcard * here denotes every vertex; for example, denotes the set of all as ranges over every vertex). The official solution2 proves that the shortest bad string, if one exists, has length at most , so the complexity of this method is reliable.
Next consider the specific hash method. The usual method—mapping a string to , and defining the hash of a multiset as the sum of the hashes of its elements modulo —does not work here. For example, the sets {"ab","cd"} and {"cb","ad"} have the same hash value regardless of how are chosen.
The problem with the method above is that the hash value of a string is a sum, so its terms can be separated and rearranged. To avoid this problem, we consider changing the hash value into a product. In addition, the commutativity of multiplication makes different positions indistinguishable, so we assign different weights to different positions to avoid this.
For every pair , where is a character and is an integer indicating the position of in a string, we pre-generate a random number . We map a string to , where is a randomly chosen prime, and define the hash of a multiset as the sum of the hashes of its elements modulo . We now analyze the error rate.
(*)Schwartz–Zippel lemma
Let be a nonzero polynomial over a field in variables of degree , and let be a finite subset of . Then at most tuples satisfy .
If you do not know what a field is
You only need to remember that both of the following are fields:
- The residue classes modulo a prime, together with their operations.
- The set of real numbers, together with their operations.
Corollary: if are independently selected uniformly from , then .
Let be the field corresponding to the residue classes modulo . For an , and correspond respectively to polynomials over in the variable set of degree . Denote these two polynomials by .
If two different string multisets have the same hash value, there are two possibilities:
- ; that is, the coefficients of every term of are equal modulo .
- ; that is, are not identically equal, but the selected happen to make their values at this point equal.
Analyze the probability of the first case:
- Observation: for any and a randomly selected prime , we have:
- This is because can hold only when satisfies , and such are counted by . By the prime number theorem, the number of distinct primes no greater than is . Dividing the former count by the latter gives the formula above.
- In the observation above, take with to be the coefficients of a particular term in (which are also the occurrence counts of the corresponding string in ). Clearly , so we obtain:
- Therefore, taking is more than sufficient. If the machine cannot support integer operations on numbers this large, double hashing can be used instead.
Analyze the probability of the second case:
- In the Schwartz–Zippel lemma:
- take the field corresponding to the residue classes modulo ;
- take to be a nonzero degree- polynomial;
- take .
- We obtain that the desired probability is .
Notice that we need to guarantee correctness for every , so for a rigorous argument we also need to use the Union Bound (see below) to explain this.
In practice, we do not need to choose the modulus randomly because—for example—using our birthday as the modulus is already equivalent to using a random number.
Example: (*) number of distinct elements in a submatrix
Problem
Given an matrix, answer queries for the number of distinct elements in a contiguous submatrix, using an online algorithm.
An error tolerance of and an error rate of are allowed; in other words, for at least queries, your answers must have relative error from the correct answer no greater than .
Lemma: let be mutually independent random variables uniformly distributed in . Then .
- Proof: consider a unit circle with points distributed uniformly at random by relative position, at positions . Then is the length of one particular segment among the gaps. Since these gaps are “symmetric”, the expected length of any particular gap is .
Take to be the number of distinct elements and use the lemma above to infer, from , the number .
Consider a hash function that maps every matrix element independently and uniformly to a real number in , with equal elements mapped to equal real numbers. Then the real numbers corresponding to all elements of a submatrix, after deduplication, form an instance of the preceding set , where equals the number of distinct elements in the submatrix.
Thus we obtain the algorithm:
- Assign a hash value in to every matrix element. To ensure randomness, the hash function can be implemented directly with
mapand a random-number generator: whenever a new value is encountered, assign it a random hash value. - When answering a query, find the minimum hash value in the submatrix and output .
However, this algorithm is not satisfactory. Its output has expectation , but in fact this is not equal to ; it is instead (as can be proved) equal to .
In other words, we cannot put a single value of directly in the denominator. We must first compute its expectation and then put the expected value in the denominator.
How do we compute the expected value? Take the average of multiple random samples.
Use different hash functions to perform the preceding process separately. When answering a query, compute different values of , take their average , and output .
Experiments show that taking is sufficient. A rigorous proof is very tedious and is omitted here.
Finally, how do we find the minimum of a submatrix? Use a two-dimensional S-T table: preprocess in time and answer each query in .
Other applications of randomization in algorithms
Other uses of randomization include:
- Preventing the data setter from defeating the algorithm with targeted data, for example by randomly shuffling the order of neighbors during a search.
- Ensuring that the operations performed during the algorithm are uniform in some sense, for example in the simulated annealing algorithm.
In these situations, randomization is often, though not always, associated with ad hoc methods and attempts to obtain points.
Example: TJOI2015 Linear Algebra
The standard algorithm for this problem is network flow, but here we use the following ad hoc method:
- Randomly choose a position each time, flip the value at that position, check the value, and update the answer.
Code
#include <algorithm>
#include <cstdlib>
#include <iostream>
int n;
int a[510], b[510], c[510][510], d[510];
int p[510], q[510];
int maxans = 0;
void check() {
memset(d, 0, sizeof d);
int nowans = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++) d[i] += a[j] * c[i][j];
for (int i = 1; i <= n; i++) nowans += (d[i] - b[i]) * a[i];
maxans = std::max(maxans, nowans);
}
int main() {
srand(19260817);
std::cin >> n;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++) std::cin >> c[i][j];
for (int i = 1; i <= n; i++) std::cin >> b[i];
for (int i = 1; i <= n; i++) a[i] = 1;
check();
for (int T = 1000; T; T--) {
int tmp = rand() % n + 1;
a[tmp] ^= 1;
check();
}
std::cout << maxans << '\n';
}
Example: (*) randomized heap3
The most common way to implement a mergeable heap is probably a leftist tree, which maintains the tree height and keeps the tree left-biased to guarantee merge complexity. However, maintaining the height is somewhat cumbersome, so we would like to avoid it as much as possible.
Thus we can consider using a randomized heap, which swaps children randomly instead of comparing their heights.
Code
struct Node {
int child[2];
long long val;
} nd[100010];
int root[100010];
int merge(int u, int v) {
if (!(u && v)) return u | v;
int x = rand() & 1, p = nd[u].val > nd[v].val ? u : v;
nd[p].child[x] = merge(nd[p].child[x], u + v - p);
return p;
}
void pop(int &now) { now = merge(nd[now].child[0], nd[now].child[1]); }
A randomized heap has no hard or soft requirements on its shape, and the expected complexity of merging any two heaps, as arguments to the merge function, satisfies the same bound. We prove this below.
Proof of the expected complexity
We prove that, for any heap , starting from the root and randomly choosing left or right at each step until no further step is possible, the expected path length (that is, the number of vertices on the path) satisfies .
- Notice that the expected complexity of merging heaps in the preceding process is , so the conclusion above guarantees the expected complexity of a randomized heap.
We use mathematical induction. The base case is the empty heap , for which the claim is obvious. Assume is nonempty.
Suppose the two subtrees of are . Then:
This proves the claim.
Proof techniques involving randomness
The following are several useful techniques.
Naturally, these few items cannot be exhaustive. If you know of a technique that is not listed, please feel free to add it.
Analysis of probability bounds
See the page on probability inequalities for details.
In addition to the inequalities mentioned on that page, the following conclusion is also frequently used in derivations:
Using the natural constant:
- The left-hand side is monotonically increasing with respect to and its limit at is , which proves the conclusion.
- This tells us that if mutually independent events each occur with probability , then the probability that they all occur is at most .
The coupling idea
The coupling idea is often used to handle more than one random object at the same time, or to handle a random object and a deterministic object simultaneously.
Prelude: connectivity of random graphs
Problem
For with , prove that the expected number of connected components of the random graph is no greater than the expected number of connected components of the random graph . Here denotes a simple undirected graph with vertices, denoted , in which each of the possible edges appears independently with probability .
This conclusion looks completely natural, but a rigorous proof is not quite so easy.
Proof idea
Imagine that the two graphs use separate 01 random number generators to determine whether each edge exists. The generator for , denoted , outputs 1 with probability , while the generator for , denoted , outputs 1 with probability . Thus, constructing a graph only requires running the corresponding generator times.
Now combine the two generators into one. Consider a random number generator that outputs 0 with probability , 1 with probability , and 2 with probability . If we run times, we can construct and simultaneously. Specifically, if the output is 0, regard the currently considered edge as absent from both and ; if it is 1, regard it as present only in ; if it is 2, regard it as present in both and .
It is easy to verify that the resulting and satisfy their definitions, and that in every instance the edge set of is a subset of the edge set of . Therefore, in every instance, has at least as many connected components as , so the same inequality naturally holds for their expectations.
The idea used in this proof is called “coupling”, which can be understood from its literal meaning. Here it consists of combining two originally independent random processes into one.
Application: NERC 2019 Problem G: Game Relics
Brief problem statement
There are several items, each with a price . You want to obtain all items, and may perform either of the following operations:
- Choose an item that you do not own and buy it for .
- Pay to draw one item uniformly at random from all items, including those already owned. If you do not yet own the item, acquire it directly; otherwise, acquire nothing but receive a refund of . Here is an input constant.
What is the expected cost under the optimal strategy?
Observation: if we choose to draw items, we will certainly keep drawing until we obtain a new item.
- Reason: if a draw does not produce a new item, the state is exactly the same as before the draw. Therefore, if the optimal action in the old state is to draw once, the optimal action in the new state must also be to draw once more.
We can define as the expected amount of money needed to draw a new item when we currently own different items. By the observation above, we can treat directly as a fixed cost, turning the process into one in which we pay each time to obtain a new item at random.
Computing the expected cost
Clearly , where is the expected number of draws needed to obtain a new item.
Lemma: if a coin lands heads with probability , the expected number of tosses until the first head is .
- Intuitively, , so tossing this many times is expected to produce one head, which seems reasonable.
- This intuition can be made rigorous using the law of large numbers, by considering experiments of “repeatedly toss a coin until obtaining heads.” Details are omitted.
- Another possible proof is to substitute directly into the definition of expectation and calculate it by brute force. Details are omitted.
Clearly, the probability of obtaining a new item on one draw is , so .
Conclusion: the optimal strategy is always to draw several times first and then buy all items that were not drawn.
This conclusion agrees with intuition, because increases with , so drawing early does indeed seem somewhat better than drawing late.
Proof
First consider a special case. We prove:
- Random process : first buy item , then keep drawing until all items are obtained.
- ……never better than……
- Random process : keep drawing until all items other than are obtained, then buy if it has not yet been obtained.
Let random processes and use the same random number generator. That is, the first draw of and the first draw of produce the same element, and the second, third, and later draws are also the same.
Clearly, and must make the same number of draws. For an item drawn by process , namely , observe that:
- The number of items already owned by when it draws is always at least the number already owned by when it draws .
Therefore, the cost of each draw in is no greater than that in , and hence the total drawing cost is no greater than 's.
Clearly, 's purchase cost is also no greater than 's. Therefore, is never worse than .
We can then generalize this conclusion to the general case by mathematical induction. Specifically, each time we find the last purchase in the current strategy, we move this purchase to the end using the conclusion above, which is never worse. Details are omitted.
Based on this conclusion, we can equivalently transform the problem again: replace the operation “choose an item and buy it for its price” with “randomly choose an item not yet owned and buy it for its price”. The operations are equivalent because, if buying is only used to clean up at the end, it does not matter which item is chosen.
We now see that drawing and buying have effectively become the same operation; the only difference is the price paid. Choosing to buy or draw has no effect on the order in which items are obtained, and every order of obtaining the items is equally likely.
Observation: at a given moment, we should choose to buy if and only if the cost of the next draw, determined by the number of items already drawn, is greater than the average price of the remaining items; if they are equal, either choice is acceptable.
- It can be proved that, over time, the draw cost increases no more slowly than the average price of the remaining items. This shows that there is only one “threshold point” at which we switch from drawing to buying, further confirming the previous conclusion.
Finally, enumerate all possible states, that is, the sets of items already owned. Calculate the probability of reaching each state, given by the number of permutations of the owned items divided by the total number of permutations, multiply it by the cost of the optimal decision in the current state, determined by the number of owned items and the total price of the remaining items, and add everything together. This process can be optimized with knapsack-style DP, which solves the problem.
Review: The coupling technique is used twice in this problem. The first time is in the proof, where the two random processes use the same random source. The second time is in transforming buying into random buying, that is, introducing a random source so that buying and drawing become essentially the same operation by having them share a random source.