思路
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]); } }