F - Hop Sugoroku

F - Hop Sugoroku

Problem Statement

There is a row of N squares labeled 1,2,,N and a sequence A=(A1,A2,,AN) of length N.
Initially, square 1 is painted black, the other N1 squares are painted white, and a piece is placed on square 1.

You may repeat the following operation any number of times, possibly zero:

  • When the piece is on square i, choose a positive integer x and move the piece to square i+Ai×x.
    • Here, you cannot make a move with i+Ai×x>N.
  • Then, paint the square i+Ai×x black.

Find the number of possible sets of squares that can be painted black at the end of the operations, modulo 998244353.

Constraints

  • All input values are integers.
  • 1N2×105
  • 1Ai2×105

Input

The input is given from Standard Input in the following format:

N
A1 A2 AN

Output

Print the answer as an integer.


Sample Input 1

5
1 2 3 1 1

Sample Output 1

8

There are eight possible sets of squares painted black:

  • Square 1
  • Squares 1,2
  • Squares 1,2,4
  • Squares 1,2,4,5
  • Squares 1,3
  • Squares 1,4
  • Squares 1,4,5
  • Squares 1,5

Sample Input 2

1
200000

Sample Output 2

1

Sample Input 3

40
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

Sample Output 3

721419738

Be sure to find the number modulo 998244353.

 

解题思路

  dp 的部分还是很容易想到的。定义 f(i) 表示在前 i 个元素中且第 i 个元素染成黑色的所有方案的数量。根据从第 i 个位置出发可到达的下标来进行状态转移,因此状态转移方程就是 f(i)f(j),j=i+kai,kZ。其中状态转移的计算量是 O(nai) 级别,如果每个 ai 都很小,那么整个 dp 的时间复杂度就会变成 O(n2)。因此只有当 ai 比较大时,这种朴素转移的计算量才会比较小。

  这时候就可以考虑用根号分治了,取 b=450(大致 2105 级别)。当 ai>b 时直接朴素转移,那么这部分整体的时间复杂度大致是 O(nnb)。当 nb 时就不能直接转移了,反过来考虑 i 能从哪些下标 j,(j<i) 转移过来,即满足 j+kaj=i 的下标 j。如果 aj 是确定的,那么就有 ji(modaj)。因此用 s[d][r] 来统计满足 jr(modd)f(j) 的总和,当枚举到 i 时,遍历 d[1,b],把 s[d][imodd] 累加到 f(i) 中,表示可以从 ajbji(modaj) 的下标 j 转移到位置 i。另外当 aib 时,只需让 s[ai][imodai] 累加 f(i) 即可。这部分整体的时间复杂度为 O(nb)

  考虑两种情况,那么总的时间复杂度就是 O(nnb+nb),其中根据基本不等式 nb+b2nbb=2n,当 nbb 相等即均取 n 时,等号成立,因此这里 b 大概取 450

  AC 代码如下,时间复杂度为 O(nn)

#include <bits/stdc++.h>
using namespace std;

const int N = 2e5 + 10, M = 460, mod = 998244353;

int a[N];
int f[N];
int s[M][M];

int main() {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d", a + i);
    }
    f[1] = 1;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= 450; j++) {
            f[i] = (f[i] + s[j][i % j]) % mod;
        }
        if (a[i] <= 450) {
            s[a[i]][i % a[i]] = (s[a[i]][i % a[i]] + f[i]) % mod;
        }
        else {
            for (int j = i + a[i]; j <= n; j += a[i]) {
                f[j] = (f[j] + f[i]) % mod;
            }
        }
    }
    int ret = 0;
    for (int i = 1; i <= n; i++) {
        ret = (ret + f[i]) % mod;
    }
    printf("%d", ret);
    
    return 0;
}

 

参考资料

  Editorial - AtCoder Beginner Contest 335 (Sponsored by Mynavi):https://atcoder.jp/contests/abc335/editorial/9038

  暴力美学——浅谈根号分治:https://www.luogu.com.cn/blog/Amateur-threshold/pu-li-mei-xue-qian-tan-gen-hao-fen-zhi

posted @   onlyblues  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
历史上的今天:
2023-01-17 D. Friendly Spiders
2023-01-17 C. Interesting Sequence
Web Analytics
点击右上角即可分享
微信分享提示