最近烦到爆炸。
题意
给一个n,表示有
n
n
n个房间,你要从1号房走到
n
+
1
n+1
n+1 号房。下一行有n个
p
[
i
]
p[i]
p[i] 值。每个房间有两个单向入口,对于第
i
i
i 号房第一个入口可以去到下一个房间,第二个入口可以去到
p
[
i
]
p[i]
p[i] 号房间,其中,
1
1
1
≤
\leq
≤
p
[
i
]
p[i]
p[i]
≤
\leq
≤
i
i
i。每去到一个房间,你就会给房间做一个标记,如果房间有奇数个标记,就走第二个入口,否则走第一个入口。初始时,第一个房间有一个标记。求走到n+1号房间是,经过多少个入口,答案求mod 1e9+7。
思路
要mod 1e9 + 7,就不能暴力啦
然后推一下样例,发现有点dp的意思
从 i = 1 -> n+1,设dp[ 1到i ]为第一次到达第 i 号房间的步数,有:
dp[ 1 到 i ] = dp[ 1 到 i-1 ] + dp[ i-1 到 i ] + 1,+1 是因为到达第i号房间时,会回第 p[i] 号房间,求dp[ 1 到 i ]的时候,已经知道了dp[ 1 到 i-1 ]。
对于dp[ i - 1 到 i ]:
dp [ i -1 到 i ] = dp[ p[i-1] 到 i -1 ] + 1,表示要从第二个路口走回 i - 1 号房,回到第 i - 1 号房需要再走第一个路口去第 i 号房,所以要+1
dp[ p[i-1] 到 i - 1] = dp[ 1 到 i -1 ] - dp[ 1 到 p[i-1] ],因为 p[i-1] <= i,所以之前肯定求过了dp[ 1到 p[i-1] ]
总结就是:dp[ 1 到 i ] = 2*dp[ 1 到 i-1 ] - dp[ 1 到 p[i-1] ] + 2,最后求mod操作注意减法可能为负数。
代码
ll dp[1005][1005],p[1005];
/*
ll dfs(int a,int b){
cout<<"dfs :"<<a<<" "<<b<<endl;
if(dp[a][b]==0){
if(a==b) dp[a ][b] = 2;
else dp[a][b] = dfs(p[a],a) + 2;
}
return dp[a][b] + 2;
}*/
int main()
{ // if(fopen("in.txt","r")) freopen("in.txt","r",stdin);
int T,n,m,k,i,sum,j,t,tmp;
scanf("%d",&n);
for(i=1;i<=n;i++) scanf("%I64d",&p[i]);
dp[1][2] = 2;
for(i=3;i<=n+1;i++){
//cout<<"dp["<<p[i-1]<<"]["<<i-1<<"] = "<<dp[p[i-1]][i-1]<<endl;
//dp[i-1][i] = (dp[p[i-1]][i-1] + 2)%mod;
//cout<<"dp["<<i-1<<"]["<<i<<"] = "<<dp[i-1][i]<<endl;
//if(p[i]==i) dp[1][i] = (2*dp[1][i-1]%mod + 2)%mod;
//else
dp[1][i] = ( 2*dp[1][i-1]%mod - dp[1][p[i-1]] + 2 + mod)%mod;
//printf("dp[%d][%d] = %I64d\n\n",1,i,dp[1][i]);
}
printf("%I64d\n",dp[1][n+1]);
return 0;
}
// = = 一开始没有想到dp[ p[i-1] 到 i - 1] = dp[ 1 到 i -1 ] - dp[ 1 到 p[i-1] ]