存在n+1个房间,每个房间依次为房间1 2 3...i,每个房间都存在一个传送门,i房间的传送门可以把人传送到房间pi(1<=pi<=i),现在路人甲从房间1开始出发(当前房间1即第一次访问),每次移动他有两种移动策略:
A. 如果访问过当前房间 i 偶数次,那么下一次移动到房间i+1;
B. 如果访问过当前房间 i 奇数次,那么移动到房间pi;
现在路人甲想知道移动到房间n+1一共需要多少次移动;
第一行包括一个数字n(30%数据1<=n<=100,100%数据 1<=n<=1000),表示房间的数量,接下来一行存在n个数字 pi(1<=pi<=i), pi表示从房间i可以传送到房间pi。
输出一行数字,表示最终移动的次数,最终结果需要对1000000007 (10e9 + 7) 取模。
2 1 2
4
开始从房间1 只访问一次所以只能跳到p1即 房间1, 之后采用策略A跳到房间2,房间2这时访问了一次因此采用策略B跳到房间2,之后采用策略A跳到房间3,因此到达房间3需要 4 步操作。
<?php fscanf(STDIN, '%d', $n); $line = fgets(STDIN); $arr = explode(' ', trim($line)); $count = 0; $i = 1; $costMap = array();//记录首次到达i房间所用的步数 $mod = 1000000007; //每次循环进入一个新房间 while (true) { if ($i == $n + 1) break; //第1次到达i房间,把count记录下。并且由1<=pi<=i可知:前面房间全部偶数次访问才能抵达该房间 $costMap[$i] = $count; //传送门,步数+1,后面就相当于已经处于传送到位的房间了 $transport = 1; //为了抵达i+1房间,需要再次回到i房间,计算要花的步数,前面的房间可以看做全都没有访问过,所以两次首次相减即可 $again = $costMap[$i] - $costMap[$arr[$i - 1]];//有可能为负,因为mod的原因。有可能为0,因为已经传送到位的本来就可能是同一个房间 //+1进入下一房间 $count = ($count + $transport + $again + 1) % $mod; $i++; } if ($count < 0) $count += $mod; echo $count. PHP_EOL;
#include <iostream> using namespace std; long long p[1001], dp[1001], n; const long long mod = 1e9 + 7; int main (){ cin >> n; for (int i = 1; i<= n; ++i) cin >> p[i]; for (int i = 2; i<= n+1; ++i) dp[i] = (2 * dp[i-1] - dp[p[i-1]] + 2) % mod; cout << (dp[n + 1] < 0 ? dp[n + 1] + mod : dp[n + 1]); }
let n = parseInt(readline().trim()); let roomArr = readline().trim().split(" "); let mod = 1000000007 let dp = new Array(n+2); dp[1] = 0 for(let i = 2;i<=n+1;i++){ dp[i]=2*dp[i-1]+2-dp[roomArr[i-2]] if(dp[i]<0){ dp[i] += mod; }else if (dp[i] >= mod){ dp[i] %= mod; } } console.log(dp[n+1])
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); final int mod = 1000000007; int[] p = new int[n+1]; int[] dp = new int[n+2]; for (int i = 1; i <= n; ++i) { p[i] = sc.nextInt(); } for (int i = 2; i <= n+1; ++i) { dp[i] = (dp[i-1] << 1) - dp[p[i-1]] + 2; if (dp[i] < 0) dp[i] += mod; else if (dp[i] >= mod) dp[i] %= mod; } System.out.println(dp[n+1]); } }
#include<iostream> #include<vector> using namespace std; const long long int mod = 1e9 + 7; int main() { int n; cin >> n; vector<int>p(n+1, 0); for(int i = 1; i <= n; i++) { cin >> p[i]; } vector<int>dp(n+2, 0);//记录第一次到达i为dp[i] dp[1] = 0; for(int i = 2; i<= n+1; i++) { dp[i] = (2*dp[i - 1] - dp[p[i - 1]] + 2) % mod; } cout << (dp[n + 1] < 0 ? dp[n + 1] + mod : dp[n + 1]); return 0; }
//直接求解可以通过60% public static void main(String[] args) { Scanner in=new Scanner(System.in); int roomNum=in.nextInt(); int[] visitedNum=new int[roomNum]; int[] transferDoor=new int[roomNum]; for(int i=0;i<roomNum;i++) { transferDoor[i]=in.nextInt()-1; } int movingCount=0;//移动次数 //从第一个房间开始 第一个房间已经过问过一次 visitedNum[0]=0; int roomID=0; while(roomID!=roomNum) { visitedNum[roomID]+=1; movingCount++; if(visitedNum[roomID]%2==0) { roomID+=1; } else { roomID=transferDoor[roomID]; } } System.out.println(movingCount%1000000007); }
#include <bits/stdc++.h> using namespace std; const int M = 1e9+7; int main(){ int n; scanf("%d", &n); int a[n], dp[n+1]; memset(dp, 0, sizeof(dp)); for(int i=0;i<n;i++) scanf("%d", &a[i]); for(int i=1;i<=n;i++) dp[i] = (2*dp[i-1]%M - dp[a[i-1]-1]+2) % M; printf("%d\n", dp[n]); return 0; }
#include <iostream> using namespace std; const int N = 1010, mod = 1e9 + 7; long long p[N], f[N]; int n,res; int main() { cin >> n; // 只会往做走 往又走只有靠走了奇数次 for(int i = 1; i <= n; ++ i) { cin>>p[i]; } // 我们要求到n + 1需要走多少次 // 可以求子问题 第二次走到n需要走多少次 // 子问题 第二次走到n - 1需要走多少次 // f[i] 如何 由 f[i - 1] 转移过来? // 我们假设f[i]记录的是到达i两次需要的次数 // f[i - 1] + 1 次到达i第一次 // 然后i走到p[i] p[i]再次走到i需要多少次 // p[i] 走到 i - 1 // 综上f[i] 表示第二次进入i需要的行程数 f[0] = 0; for(int i = 1; i <= n ; ++i) { // f[i] += f[i - 1] + 1; int j = p[i]; // f[i] += (f[i - 1] - f[j - 1] + 1); f[i] = (2*f[i - 1] - f[j - 1] + 2) %mod; } cout<<(f[n] + mod ) % mod<<endl; return 0; } // 64 位输出请用 printf("%lld")
import java.util.*; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int[] ps = new int[n + 1]; int index = 1; while (index <= n) { ps[index ++] = sc.nextInt(); } long[] dp = new long[n + 1]; dp[0] = 0L; dp[1] = 2L; for (int i = 2; i <= n; i ++) { dp[i] = 2 * dp[i - 1] - dp[ps[i] - 1] + 2; dp[i] = dp[i] < 0 ? dp[i] + 1000000007 : dp[i] % 1000000007; } System.out.println(dp[n]); } }
n=int(input()) pi=list(map(int,input().split())) dp=[0 for i in range(n+1)] for i in range(1,n+1): #dp[i]第一次到i所需的移动次数,此处的i就是n+1 dp[i]=(dp[i-1]+(dp[i-1]+1-dp[pi[i-1]-1])+1)%1000000007 print(dp[-1])
const ll mod = 1000000007; ll dp[1010];//对于一个点从偶次状态到偶次状态的最小步数 int p[1010]; int n; void solve(){ cin >> n; for(int i = 1; i <= n; i++){ cin >> p[i]; } ll ans = 0; for(int i = 1; i <= n; i++){ if(p[i] == i){ ans = (ans + 1ll * 2) % mod; dp[i] = 1ll * 2; } else{ ll now = 0; for(int j = p[i]; j < i; j++){ now = (now + dp[j]) % mod; } (now = now + 2ll) % mod; dp[i] = now; ans = (ans + now) % mod; } } cout << ans << "\n"; }这个题我们会发现,对于首次到一个点i,到达1 ~ i - 1的点都经过了偶数次,所以我们处理出每一个点从经历偶数次到经历偶数次的步数用dp[i]表示即可,这只是一个思维题,其实O(n)复杂度就能过。