长路

长路

题目描述

一天,小Vasya发现自己在一个有(n+1)个房间的迷宫里。刚开始,Vasya在第一个房间,为了走出迷宫,他必须到达第(n+1)个房间。

迷宫的构造是这样的:每个房间有两个单向传送门。考虑第i个房间,我们可以使用第一个传送门前往第i+1个房间,也可以使用第二个传送门前往第pi个房间,这里 1≤pi≤i

为了防止迷路,Vasya决定按以下方式走出迷宫:

每次进入某房间,就在天花板上画一个X。刚开始,Vasya在第一个房间画一个X
假设Vasya在第i个房间,而且已经画了X。然后,如果天花板上有奇数个XVasya会使用第二个传送门,否则使用第一个。
帮助Vasya计算他需要使用多少次传送门才能到达第n+1个房间。
数据范围

测试点 n
1~2 ≤5
3~5 ≤20
6~7 ≤100
8~15 ≤1000
16~20 ≤10^6

输入格式 2072.in

第一行一个整数n n ≥ 1

第二行n个整数,第i个表示pi

输出格式 2072.out

你的答案除以1 000 000 007的余数。

输入样例 2072.in

2
1 2

输出样例 2072.out

4

       首先,想想纯模拟。也就是到达每一个点,判断X的奇偶,然后一步一步走。光看输出格式就可以知道,答案很大,超时是一定的。

   得分:25。

   下面进行优化。一步一步走太慢,那就一次走多步,进行递推。可以发现,到达一个点,都会经历这样的故事——启动二类防护门,从p[i]往i走一次;到达i后再启动一类防护门,到达i+1。很显然,p[i]往i走一次的步数可以在之前的计算中得到。由此,状态的定义、转移如下:

   f[i]表示到达i后,直到到达i+1所需的步数。

   f[i]=2+sigma(f[p[i]]+f[p[i]+1]+。。。。+f[i-1]);

   时间复杂度O(N*N),得分75。

   很显然,f[p[i]]+f[p[i]+1]+。。。+f[i-1]是连续的,因而可以用部分和进行优化。方程可简化为f[i]=2+sum[i-1]-sum[p[i-1]-1]。

   不过,由于此处的f/sum都是取模后的结果,因此sum[i-1]和sum[p[i-1]]的大小关系不确定,造成答案的错误。根据模的原理,if(sum[i-1]< sum[p[i-1]])f[i]=(2+(mod+sum[i-1]-sum[p[i]-1])%mod)%mod;

   最后输出sum[n]即可。

   时间复杂度:O(N)得分100。

   PS:看到时间复杂度大的题目,不要当即头大。考试时就要推一推,算一算。这题真心不难……

   代码如下:

#include<iostream>

#include<cstdio>

using namespace std;

const int MAXN=1e6+5;

long long n;

int p[MAXN];

long long f[MAXN],sum[MAXN];

long long mod=1000000007;

int main()

{

    cin>>n;

    for(inti=1;i<=n;i++)   cin>>p[i];

    f[1]=2;

    sum[1]=2;

    for(inti=2;i<=n;i++)

    {

        if(sum[i-1]>sum[p[i]-1])    f[i]=(2+sum[i-1]-sum[p[i]-1])%mod;

        else    f[i]=(2+(mod+sum[i-1]-sum[p[i]-1])%mod)%mod;

        sum[i]=(sum[i-1]+f[i])%mod;

    }

    cout<<sum[n]<<endl;

    return0;

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值