2020.11.2
题目描述
奥尔加在一个长度为 (n+1) 的街道上跑着,初始,奥尔加在位置 (1) 上,他想要跑到位置 (n+1) 去保护团员 ride on。空旷的大路上难免会有暗杀者,当奥尔加走到位置 (i) 时,会有暗杀者出现,这时奥尔加只能回到 (p_i (1leq p_ileq i)) 位置上,但在下次到达 (i) 的时候,暗杀者就不会出现(如果再到达 (i) 还会有暗杀者),换言之,当奥尔加此时是第奇数次到达 (i) 的时候,下一步会走到 (p_i),第偶数次到达 (i) 的时候,下一步走到 (i+1)((n+1) 位置上没有暗杀者)。奥尔加每次移动都需要花费 (1) 单位时间,停不下来的奥尔加只会一直跑,他想知道自己什么时候才能到达 (n+1) 位置,因为答案可能会很大,你只需要告诉他答案对 (1000000007 (10^9+7)) 取模的结果就好了。
解法
一开始想的分层图,什么玩意儿啊……后来想dp,最后三分钟把式子推出来了……没时间写
记 (dp_i) 表示第一次走到 (i) 的时候是第几步,那么答案就是 (dp_{n+1})。
(f_i) 表示当前在位置 (i),跳到 (p_i) 后再次到达位置 (i) 需要的步数。
那么
[egin{cases}
dp_1=0 \
f_1=1 \
dp_n=dp_{n-1}+f_{i-1}+1 \
f_n=(sum_{i=a_i}^{n-1} f_i+1)+1
end{cases}]
对 (f_n) 的转移前缀做差即可。
#include<stdio.h>
#define ll long long
#define N 1000007
#define Mod 1000000007
inline int read(){
int x=0; bool flag=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-') flag=0;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
return flag? x:-x;
}
ll dp,f[N],s[N];
int n,a[N];
int main(){
freopen("rideon.in","r",stdin);
freopen("rideon.out","w",stdout);
n=read(),a[1]=read();
dp=0,f[1]=s[1]=1;
for(int i=2;i<=n;i++){
int x=read();
dp=(dp+f[i-1]+1)%Mod;
f[i]=((s[i-1]-s[x-1]+i-x+1)%Mod+Mod)%Mod;
s[i]=(s[i-1]+f[i])%Mod;
}
printf("%lld",dp+f[n]+1);
}