Google Code Jam 2021 R2 Matrygons 题解

比赛的时候想错方向了:disappointed:

Solution #

设从里向外多边形的边数为e1,e2,,ene1, e2, \dots, e_n。不难发现eie_i必须是ei1e_{i-1}的倍 数,因此我们可以把ee写成e11,e1k2,,e1kne_1\cdot 1, e_1\cdot k_2, \dots, e_1\cdot k_n。所以 如果我们知道最里面的多边形的边数,那么剩下的事情就是找到最长的序列k1=1,k2,k3,,knk_1=1, k_2, k_3, \dots, k_n 使得kik_iki1k_{i-1}的倍数并且iki=K\sum_i k_i=K

注意k2,k3,,knk_2, k_3,\dots, k_n都是k2k_2的倍数,所以如果我们把它们都除以k2k_2就又得到 了一个以11开头的序列!也就是说我们得到了一个更小的子问题,所以我们可以用动态规 划来解决:设dpidp_i为和为ii的上述序列的最大长度。因为我们可以把一个短的序列乘上 一个数并在最前面放一个11,从而得到一个更长的序列,所以状态转移就是: 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

代码 #

#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;
}