In round 2’s problem B “Matrygons”, we want to nest regular polygons within each other so that they all have all of their vertices on the same circle without crossing lines.
The puzzle gives a number of edges \(N\) and asks how many polygons we can squeeze in this way such that the sum of their number of edges is \(N\).
Very artificial.
Two regular polygons that nest within the same circle necessarily have a number of edges one a multiple of the other. The minimum number of edges to form a polygon is \(3\). So we are searching for the longest possible sequence of integers \(f_1, f_2 \ldots f_k\) such that:
\[ \begin{cases} f_1\ge 3 \\ \forall i>1, f_i\ge 2 \\ \sum_{k=1}^n \prod_{i=1}^k f_i=N \end{cases} \]
Solving for a given \(N\) is rather inconvenient. On the other hand, computing all of them once for later querying isn’t too complex. The process is very similar to array-based Eratosthenes sieving, though the complexity is a bit more since we can’t skip composites anymore. I find \(O(N \log N)\).
-- | Compute a solution look-up table up to N.
solve :: Int -> UArray Int Int
= runSTUArray $ do
solve hi <- newArray (1,hi) 0
ns let go sides polygons s = do
let sides' = sides+s
= polygons+1
polygons' <= hi) $ do
when (sides' <- readArray ns sides'
n let n' = max polygons' n
writeArray ns sides' n'mapM_ (go sides' polygons') [2*s,3*s..hi-sides']
mapM_ (go 0 0) [3..hi]
pure ns
The go
helper recursively computes the matrygon settings
for a given inner content, summarized as an (outer polygon edge count,
polygon count) pair.
The wrapper follows. It takes advantage of lazyness to have the same program able to answer on both test set sizes.
main :: IO ()
= do
main <- readLn :: IO Int
t let cacheSmall = solve 1000
= solve 1000000
cacheLarge 1..t] $ \i -> do
forM_ [<- readLn
n let cache | n <= 1000 = cacheSmall
| otherwise = cacheLarge
putStrLn $ "Case #" ++ show i ++ ": " ++ show (cache ! n)
This concludes today’s problem. The same code is on GitHub as per usual. See you soon!