思路

dp状态定义为第一次抵达i号房间时已经产生的移动次数,即dp[]数组中存储的数据的含义

注意关注到两点:
第一点:当移动到i号房间时,意味着前方所有的房间的访问次数均为偶数次,否则不会到达i号房间
第二点:从i-1号房间跳到前方的pi号房间后,再次移动到i-1号房间的移动路径为A,第一次抵达pi号房间,到第一次抵达i-1号房间的移动路径为B,A和B是完全一样的,所以两次移动过程产生的移动次数也是一样的,因为可以根据路径B来作差求出A路径中产生的移动次数

import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        run();
    }

    public static void run() {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] pi =  new int[n + 1];
        for (int i = 1; i <= n; i++) {
            pi[i] = sc.nextInt();
        }
        // 第一次到达i号房间时所需要的次数
        long[] dp = new long[n + 1 + 1];
        long mod = 1000000007;
        for (int i = 2; i <= n + 1; i++) {
            if (pi[i - 1] == i - 1) {
                // 如果i-1号房间的跳跃房间是自己
                // 甲第一次到达i-1号房间时已经产生的移动次数是dp[i-1]
                // 由dp[i-1]再跳两次就能够到达i号房间
                dp[i] = dp[i - 1] + 2;
            } else {
                // 甲第一次到达i-1号房间时,已经产生的移动次数是dp[i-1],此时前方所有的房间的访问次数均为偶数次,否则到达不了i-1号房间
                // 如果i-1号房间的跳跃房间是前方的房间,则甲跳跃到pi号房间,会导致pi号房间由偶数次访问增加一次访问之后达到奇数次访问,此时甲从pi号房间重新到达i-1号房间所需要的移动路径,与甲第一次到达pi号房间再由pi号房间第一次到达i-1号房间的移动路径是一样,意味着移动次数也会相同,所以再次从pi号房间移动到i-1号房间产生的移动次数与第一次到达i-1号房间减去第一次到达pi号房间的次数之差是一样的
                // +1 跳跃到pi号房间
                // dp[i-1] - dp[pi[i-1]] 从pi到达i-1所需要的次数
                // +1 从i-1到i
                dp[i] = dp[i - 1] + 1 + (dp[i - 1] - dp[pi[i - 1]]) + 1;
            }
            dp[i] %= mod;
        }
        System.out.println(dp[n + 1] < 0 ? dp[n + 1] + mod : dp[n + 1]);
    }
}