Codeforces - Long Path (dp)

最近烦到爆炸。

题目

题意
给一个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] ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值