题目:
分析:
很明显是一个顺推的dp。
首先分析题目的性质:
如果现在向回走到了一个点,那么那个点一定是第奇数次被经过(离开它的时候一定是被偶数次经过)
定义dp [ i ]为到达i时是奇数次,再离开i,然后走到 i+1 所花费的时间。
答案就是dp[ n ]。
考虑怎么转移:
dp[ i ]=dp[ pi ] + dp[ pi+1 ]……dp[ i-1 ]。
就是先往回跳到pi,然后再花费dp[ pi ]的时间跳到pi+1,一直到 i点。
但是这样还不够,从i跳回pi花费了1的时间,回到 i 之后又花费了1的时间跳到 i+1,所以要在上式基础上+2.
最后维护一下前缀和就可以O(n)递推了。
#include<bits/stdc++.h> using namespace std; #define N 1000005 #define ll long long #define ri register int const int mod = 1e9+7; int n,p[N],tim=0; ll dp[N],sum[N]; /* int cnt[N]; void dfs(int now) { if(now==n+1) { printf("%d\n",tim); exit(0); } cnt[now]^=1; tim=(tim+1) %mod; if(cnt[now]&1) dfs(p[now]); else dfs(now+1); }*/ int read() { int x=0,fl=1; char ch=getchar(); while(ch<'0' || ch>'9') { if(ch=='-') fl=-1; ch=getchar(); } while(ch<='9' && ch>='0') x=x*10+ch-'0',ch=getchar(); return x*fl; } int main() { freopen("rideon.in","r",stdin); freopen("rideon.out","w",stdout); scanf("%d",&n); for(ri i=1;i<=n;++i) p[i]=read(); for(ri i=1;i<=n;++i){ ll tot=0; if(i-1>=p[i]) tot=( (sum[i-1]-sum[p[i]-1]) %mod +mod) %mod; dp[i]=tot+2; sum[i]=(sum[i-1]+dp[i]) %mod; } printf("%lld\n",sum[n] %mod); //dfs(1); return 0; } /* 2 1 2 5 1 1 1 1 1 2 1 1 3 1 1 1 4 1 1 1 1 7 1 1 2 2 3 2 4 8 1 2 1 1 3 2 2 4 41 1 1 1 1 4 1 1 2 2 5 7 1 5 7 11 3 8 3 2 11 9 8 15 4 7 1 5 6 1 17 26 19 21 33 32 3 5 29 11 27 23 31 */