停不下来的团长奥尔加(一道递推题,思维很好啊....)

停不下来的团长奥尔加
【题目描述】
奥尔加在一个长度为n+1的街道上跑着,初始,奥尔加在位置1上,他想要跑到 位置n+1去保护团员ride on。
空旷的大路上难免会有暗杀者,当奥尔加走到位置i时,会有暗杀者出现,这时奥 尔加只能回到pi(1≤pi≤i)位置上,但在下次到达i的时候,暗杀者就不会出现(如果再到 达i还会有暗杀者),换言之,当奥尔加此时是第奇数次到达i的时候,下一步会走到pi, 第偶数次到达i的时候,下一步走到i+1(n+1位置上没有暗杀者)。
奥尔加每次移动都需要花费1单位时间,停不下来的奥尔加只会一直跑,他想知道 自己什么时候才能到达n+1位置,因为答案可能会很大,你只需要告诉他答案对 1000000007(109+7)取模的结果就好了。
【输入描述】
第一行一个整数n,含义同题中所述。
第二行n个整数,第i个数表示pi,含义同题中所述。
【输出描述】
一行一个整数,表示答案对1000000007(109+7)取模后的结果。
【样例输入1】
2 1 2
【样例输出1】
4
【样例1解释】
初始奥尔加在位置1上,因为这是他第1次到达位置1,所以第一步他会走到pi=1 上,此时的位置1已经到达了两次,所以第二步奥尔加会走到1+1=2位置上。
同样的,奥尔加接下来会走p2=2,2+1=3,一共花费4步到达n+1位置。
【样例输入2】
4 1 1 2 3
【样例输出2】
20
【样例输入3】
5 1 1 1 1 1
【样例输出3】
62
【样例3解释】
你真的忍心让我全部列出来吗,所以说,不要停下来啊(指偷懒)。
【数据范围与约束】
对于10%的数据,保证1≤n≤20;
对于另外10%的数据,满足pi=i;
对于另外20%的数据,满足pi=1;
对于另外20%的数据,保证1≤n≤1000;
对于100%的数据,保证1≤n≤1000000,1≤pi≤i。

//这道题我真的没有想出来,打了个40分的暴力就拜拜了。。。。。

dp[i]表示第一次从1走到i所需要时间。

dp[i] = dp[i-1] + 1 + dp[i-1] - dp[p[i-1]] + 1;

解释一波:第一次从1走到i所需要时间 = 第二次走到i-1的时间 + 1;

dp[i-1]为第一次走到i-1的时间。

第一个+1是从i-1走到p[i-1]需要1s。

而到p[i-1]并不会直接往前走而是往回跳跳p[p[i-1]]。一直跳到一个点j,满足p[j] = j,然后再往前跳跳到i-1.

上面过程的所需时间怎么算呢?就是dp[i-1] - dp[p[i-1]]

第一次到 i-1时肯定已经到p[i-1]两次或者以上,而跳回p[i-1]可以看成第1次到p[i-1],那么

要从p[i-1]往回跳,再跳回i-1的时间就是dp[i-1] - dp[p[i-1]。

第二个+1是从i-1到i的时间。

#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
int  n, p[1000005], tiao[1000005];
long long f[1000005];
void read(int &x)
{
	x = 0;   char c = getchar();   int f = 0;
	while(c < '0' || c > '9')
	{
		if(c == '-') f = 1;   c = getchar();
	}
	while(c >= '0' && c <= '9')
	{ 
		x = 10 * x + c - '0'; c = getchar();
	}
	if(f) x = -x;
}
int main()
{
	freopen("rideon.in","r",stdin);
    freopen("rideon.out","w",stdout);
	int ha = 0;
   read(n);
     for(int i = 1; i <= n; i++)
     {
     	scanf("%d",&p[i]);
     }
     f[1] = 0;
   	for(int i = 2; i <= n + 1; i++)
   	{
   	    f[i] = (2ll * f[i-1] % mod - f[p[i-1]]  +mod + 2)%mod;
   	}
   	cout << f[n+1];
   	return 0;
} 

如此小清新的题,我总是不能很好的找到递推关系=。=

猜你喜欢

转载自blog.csdn.net/Bluelanzhan/article/details/83450504