Challenge24 2013 writeups

Electronic contest - B. Requirements

In an iteration every ordered pair of manuals is merged into a new manual (a manual is merged with itself: old manuals are kept). So the number of manuals are squared in an iteration, but the number of manuals with a given requirement set (bit pattern) increases in a non-obvious way.

So instead of counting the number of manuals having exactly a given requirement set, try to count the manuals that have a subset of the given requirements (for all 2^N possible requirement selection):

So using modulo exponentiation an efficient solution is

	// using that 2^(MOD-1) % MOD == 1
	e = modexp(2, T, MOD-1)

	// do transformations inplace
	tosubset(Counts)
	for i = 0 .. 2^N-1 {
		// Counts[i] = Counts[i]^(2^T) % MOD
		Counts[i] = modexp(Counts[i], e, MOD)
	}
	fromsubset(Counts)
	// solution is Counts[2^N-1];
where Counts is the array that holds the initial manual counts for every requirement set, MOD=1000000007 is prime and tosubset and fromsubset are linear transfomations that change to and from requirement subset counting.

A possible implementation of tosubset and fromsubset

	// call it as tosubset(Counts, 0, 2^N)
	void tosubset(int Counts[], int start, int len)
	{
		len = len / 2
		if len == 0 {
			return
		}
		tosubset(Counts, start, len)     // transform first half: starts with 0 bit
		tosubset(Counts, start+len, len) // transform second half: starts with 1 bit
		for i = 0 .. len-1 {
			// first half is a subset of second half
			Counts[start+len+i] = (Counts[start+len+i] + Counts[start+i]) % MOD
		}
	}

	void fromsubset(int Counts[], int start, int len)
	{
		len = len / 2
		if len == 0 {
			return
		}
		for i = 0 .. len-1 {
			Counts[start+len+i] = (Counts[start+len+i] - Counts[start+i] + MOD) % MOD;
		}
		fromsubset(Counts, start, len)
		fromsubset(Counts, start+len, len)
	}