题目链接:http://codeforces.com/contest/407/problem/B
题意:给你 n+1 个按顺序编号的房子,每个房子两个门,第一个是走向下一个房间,另一个门是走向以前走过的房间,此数据由输入给定。求从1走到 n+1 要多少步。
思路:很逊,刚开始直接用暴力模拟,于是超时了。后来想到记录下从1走到 i 的步数,可用 d[i] 表示,那么从 i 走到 i + 1 就只要 1 + d[pi] + d[pi+1] +...+ d[i-1] + 1 步。在累加的过程注意取模。其实就是个简单的动规,找到动规递推表达式就简单多了 dp[i+1] = 2dp[i] +2 - dp[pi] 。 即 从1 走到 i 加上 从 pi 走到 i 再加上 从 i + 1 到 i 和 i 到 i +1 的两步。动规本来就是比较宏观的解法,我却去找里面的细节,越搞越复杂。尽管最终用自己的想法做出来了,但看别人写的解题报告,自己还需要更加努力。看到动规就应该学者去找递推公式,不然只会越想越难。
我的代码:
#include <stdio.h>
#include <string.h>
#define MAXN 1010
#define MD 1000000007
int main(){
int i, n, cnt;
int p[MAXN];
int ans[MAXN];
memset(ans, 0, sizeof(ans));
scanf("%d", &n);
for(i = 1; i <= n; ++i)
scanf("%d", p+i);
ans[1] = 2;
cnt =0;
for(i = 2; i < n+1; ++i){
ans[i] = ans[p[i]] + 2;
int t = p[i] + 1;
while(t < i){
ans[i] += ans[t++];
ans[i] %= MD;
}
}
for(i = 1; i < n+1; ++i){
cnt = ans[i] + cnt % MD;
}
printf("%d\n", cnt % MD);
return 0;
}
直接模拟超时代码:
#include <stdio.h>
#include <string.h>
#define MAXN 1010
#define MD 1000000007
int main(){
int i, n, cnt;
int p[MAXN];
int rc[MAXN];
memset(rc, 0, sizeof(rc));
rc[1] = 1;
scanf("%d", &n);
for(i = 1; i <= n; ++i)
scanf("%d", p+i);
i = 1;
cnt = 1;
while(i < n+1){
rc[i]++;
if(rc[i] % 2 == 0){
++i;
} else {
i = p[i];
}
cnt = (cnt + 1) % MD;
}
printf("%d\n", cnt);
return 0;
}