Solution for Google Code Jam 2021 R2 Matrygons

DP Solutions

Went the wrong direction during the contest. :disappointed:

Solution #

Let the number of edges of the polygons be e1,e2,,ene1, e2, \dots, e_n. It’s easy to find that eie_i has to be a multiple of ei1e_{i-1}, thus we can rewrite ee as e11,e1k2,,e1kne_1\cdot 1, e_1\cdot k_2, \dots, e_1\cdot k_n. Hence if we know the number of edges of the first polygon, all we left if to find the longest sequence k1=1,k2,k3,,knk_1=1, k_2, k_3, \dots, k_n such that kik_i is a multiple if ki1k_{i-1} and iki=K\sum_i k_i=K.

Note that k2,k3,,knk_2, k_3,\dots, k_n are all multiple of k2k_2, so if we divide them by k2k_2 we get a sequence starting with 11 again! This means we get a smaller subproblem and we can use dynamic programming to solve it: let dpidp_i be the length of the longest such sequence described above which sums to ii. Since we can get a longer sequence by multiplying a shorter one by a constant and prepending a 11, so the transition is: dpki+1max(dpki+1,dpi+1),k=2,3,dp_{k\cdot i+1}\coloneqq \max(dp_{k\cdot i+1}, dp_i+1), k=2,3,\dots

Code #

#include <bits/stdc++.h>
 
using namespace std;
 
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int tt = 1;
    cin >> tt;
    constexpr int N = 1e6;
    vector<int> dp(N + 1, 1);
    for (int i = 1; i <= N; i++) {
        for (int j = 2 * i + 1; j <= N; j += i) {
            dp[j] = max(dp[j], dp[i] + 1);
        }
    }
    for (int cas = 1; cas <= tt; cas++) {
        int x;
        cin >> x;
        int ans = 1;
        cout << "Case #" << cas << ": ";
        for (int f = 3; f <= x; f++) {
            if (x % f == 0)  ans = max(ans, dp[x / f]);
        }
        cout << ans << '\n';
    }
    return 0;
}