Some Programming Puzzles
I hastefully prepared a few programming puzzles for a little casual contest
last year, and I never did anything afterwards... In the rare case that you
want to verify a solution, I can either add you to the Codeforces group from
last year (that's where it was held), or send you everything needed to run
the judge yourself.
The problem statements from last year are honestly
a bit difficult to read, but somehow the four people that participated could
read them without me having to clarify anything. Weird. You will have to read
that for any chance of having the context for anything below though. One thing
in common is weird and bolted-on story lines. Bear with them (evil)
I'll skip the first problem because I really needed to consider if whitespace
and capitalization in a gender specification should be meaningful, and even
if everybody agrees it shouldn't, the solution to the programming problem
is not very interesting. On to the second problem :3
Trans Rights 🏳️⚧️
(a whopping two (2) trans pride flags on this page!)
I did end up letting bruteforce solutions pass (one of them passed and another
didn't, for some reason), so maybe the problem sizes
should be a bit more than that, 3×104 or something like that.
The computers working for Codeforces and Codeforces Polygon seem to be different,
and I was not able to determine an appropriate bound that work for both websites.
There is a simple dynamic programming solution to the problem on a sequence.
Consider recording the number of possible ways to walk through a sequence of
character sets and appending the substring of 'transrights' starting from
i to j (indices start from 1, for implementation conveniences)
as a matrix, then C(i,j) can be found in the matrix. When we
concatenate two sequences of character sets, the corresponding matrix multiplies.
In order to use this idea on the tree we're given, we need to use heavy-light
decomposition and split the query into at most O(logn) subqueries
that lie on the same path, and use a data structure that can handle single-point
modifications and interval semigroup products. Because a path can be walked in
two different directions and matrix multiplication is not commutative, we need
two different instances, with their definitions for multiplication to be regular
matrix multiplication for one of them and the opposite for the other.
There are a few constant factor optimizations you need, but honestly they are
not very interesting. Sometimes (a + b >= p) ? a + b - p : a + b
is
faster than (a + b) % p
(when a and b are already natural numbers less
than p), and when doing the matrix multiplication,
in the second loop in, put the entry you're multiplying others with in a local
variable, avoid doing the empty half of the lower triangle matrix, etc.
I tried to make the solver reflect on the assumptions data structures impose
on the algebraic structure of the stuff being computed (when I was learning
them, tutorials were like "let's add together numbers written on weird
shapes!" sure, weird shapes are weird, but numbers can also be weird!),
but the problem ended
up being a bit lame :( Segment trees basically solves the whole "single-point
modification with interval associative product" problem once and for all.
Fenwick trees need an
Abelian group to work with (for interval product and not just prefix product)
and it's a mere constant factor optimization over using a segment tree.
Hash
This problem is somewhat of a paper tiger because there definitely is a way
of guessing to an accepted program, but the problem ended up unsolved! (should
I really be excited? it could be a technical problem)
Anyways! By viewing the 2k's digit in a 32-bit unsigned integer as
the coefficient for the xk term in a polynomial with coefficients in
F2, the uint32_t
's corresponds nicely to elements in
F2[x]/(p)≈F232:=F (that p is indeed irreducible), and
that's basically it. XORing the integer is adding the polynomial, and
conv
-ing the integer is multiplying the polynomial modulo the polynomial
corresponding to p
. The length of the answer is 1 iff a↦ak
is not an automorphism, and that's equivalent to gcd(k,∣F×∣)>1.
We can guess a primitive root g once and output 1 and
g∣F×∣/gcd(k,∣F×∣) in this case.
If we couldn't find a collision of length 1, we definitely can find one of
length 2 by the pigeonhole principle. Just fixing three elements and solving
for the rest is enough. When you want to compute a multiplicative inverse
using exponentiation, do note that the order of the multiplicative group is
(232−1) and not φ(232).
Pie
Bruteforcing and printing out the answer for some points tells us that answers
are small, in fact no more than 9. It might be possible to have a table of
which answers comes from where, considering the answers viewed as a sequence
is also roughly increasing. Adding it with itself shifted one place takes care
of the roughness as a whole though. Just bisect the minimum i satisfying
Ai+Ai+1=k (Ai for answer at i) for every
k and you're good to go! Note that
double precision floats are not precise enough if you add the terms naively.
Use a fixed-point number with bigints.
noitatumreP
This is not very interesting imo as it's mostly manipulating stuff, but I'll
explain everything anyways.
See that (⋅)+1 on the denominator? That's what you get integrating
x(⋅) from 0 to 1. That (−1)τ(p)? From a determinant.
Let Mn be the n×n matrix with x on the main
diagonal and 1 on the two diagonals adjacent to the main one, then
detMn has the terms we need. We just need to calculate the sum of
coefficients of all terms in detMn with an exponent congruent to
every k modulo m. But since
detMn=xdetMn−1−detMn−2, we can encode the sums for Mn
and Mn−1 into a vector and multiply a transition matrix onto it
n times. If you're not careful you might trip up when m=1
because you're assigning entries in the transition matrix and not accumulating
them.