题解:#8265.「JXOI Round 2」黑白 审核通过

jxy2012 qwq 2024-06-30 8:38:32 7

涂黑的一组方格与棋子前进的方式相对应,因此只需计算后者即可。

现在,让我们忽略计算复杂性,专注于解决问题。它可以归结为 DP(动态编程),用下面的伪代码表示:

dp={1,0,...,0};
for(i=1;i<=N;i++)
    for(j=i+A[i];j<=N;j+=A[i])
        dp[j]+=dp[i];
print(sum(dp));

较大时, 上的迭代不会重复很多次,所以这种方法似乎是合理的,但如果以 为例,则需要花费 时间,所以这种算法很难通过。

取而代之的是,让我们考虑如何在 很小的情况下快速更新 DP 数组。

对于 ,当且仅当 的倍数(即 除以 的余数等于 除以 的余数)时,才会发生从 的转换。

因此,如果我们定义一个数组,如 {除以 的余数是 },问题似乎又可以迎刃而解了(事实的确如此)。

那么, 是 "小" 还是 "大 "呢?

假设 是 "小" 和 "大" 的边界。

  • 如果对小 进行操作,该部分的时间复杂度为
  • 如果对大型 进行操作,则该部分的时间复杂度为

为了使 最小化,让 最小化是最优的(简短证明:算术和几何平均数不等式)。
实施时,可以将 固定为 附近的任意常数。根据常数的不同,最佳的 可能与 相差甚远,因此在某些情况下不妨多试几次。

至于如何正确实现,留给读者自己去探索。我们将在社论后展示示例代码。

处选择一个边界或分割成 个数据包以快速求解子问题的技术称为根号分治

{{ vote && vote.total.up }}