Codeforces 407B Long Path(好题 DP+思维)
题目链接:http://codeforces.com/problemset/problem/407/B
题目大意:
一共n+1个房间,一个人从1走到n+1,每次经过房间都会留下一个标记,每个房间有两扇门:
①第一扇门通向i+1,如果当前房间标记有奇数个,则必须走第一扇门。
②第二扇门通向pi(pi<=i),如果当前房间标记有偶数个,则必须走第二扇门。
问从房间1走到房间n+1需要多少步,结果对1e9+7取模。
解题思路:
之前傻了。。。明明都推出规律了,结果被自己给否定了。。。
设dp[i]表示从1~i需要走多少步,那么我们可以得到状态转移方程:
dp[i+1]=dp[i]+dp[i]-dp[p[i]]+2=2*dp[i]-dp[p[i]]+2
下面来解释一下,如果当前走到了i点,那么i点之前的所有点的标记数肯定都是偶数,因为只有标记为偶数才能往后走。
偶数可以看成是0,相当于跟第一次走一样。这里的2是因为从i到p[i]需要一步,从i到i+1需要一步。
从1~i为的步数为dp[i],然后返回p[i],从p[i]~i的步数为dp[i]-dp[p[i]],所以总步数就是dp[i]+dp[i]-dp[p[i]]+2=2*dp[i]-dp[p[i]]+2。
代码
1 #include<bits/stdc++.h> 2 #define lc(a) (a<<1) 3 #define rc(a) (a<<1|1) 4 #define MID(a,b) ((a+b)>>1) 5 #define fin(name) freopen(name,"r",stdin) 6 #define fout(name) freopen(name,"w",stdout) 7 #define clr(arr,val) memset(arr,val,sizeof(arr)) 8 #define _for(i,start,end) for(int i=start;i<=end;i++) 9 #define FAST_IO ios::sync_with_stdio(false);cin.tie(0); 10 using namespace std; 11 typedef long long LL; 12 const int N=1e5+5; 13 const int MOD=1e9+7; 14 const int INF=0x3f3f3f3f; 15 const double eps=1e-10; 16 17 LL dp[N]; 18 int p[N]; 19 20 int main(){ 21 FAST_IO; 22 int n; 23 cin>>n; 24 for(int i=1;i<=n;i++){ 25 cin>>p[i]; 26 } 27 for(int i=1;i<=n;i++){ 28 dp[i+1]=(2*dp[i]-dp[p[i]]+2+MOD)%MOD; 29 } 30 cout<<dp[n+1]<<endl; 31 return 0; 32 }