CF407B Long Path

CF407B Long Path

递推题,好好打草稿 + 好好读题其实可以较快做出,但今晚情绪不好做着玩的,也就没太在意。

发现走到 \(i\) 的状态跟走来的过程完全无关,只在乎起点是谁(走过来的过程可以由起终点完全确定,因此贡献也就确定了)。因此记 \(f_i\) 表示从 \(i - 1\) 走到 \(i\) 需要几步。

详细写一下样例的每一步,就会发现形如 \(1\ 1\ 1\ 1\ 1\) 的结果是 \(2\ 4\ 6\ 8\ 16\) 这样排布的,然后就是考虑 \(p_i \ne p_{i + 1}\) 怎么做,分两类:

第一类,\(p_{i - 1} = i - 1\),则不用再回去,\(f_i = 2\)。

第二类,\(p_{i - 1} < i - 1\),那就回到 \(p_{p_{i - 1}}\),再走到 \(i - 1\),这样到 \(i - 1\) 就是偶数个十字架了,\(f_{i} = s_{i - 1} - s_{p_{i - 1}} + 2\)。\(s_i\) 就是 \(f_i\) 的前缀和。

不难发现每次回到 \(p_{p_{i - 1}}\) 时它都会画上第奇数个十字架,所以每次到 \(i - 1\) 的路径时一样的。想清楚这一点后理解起来就比较清楚了。

发现两类情况可以合并。

于是 \(O(n)\) 做完了。

#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l); i <= (r); ++ i)
#define G(i,r,l) for(int i(r); i >= (l); -- i)
using namespace std;
using ll = long long;
const int N = 2e3;
const int mod = 1e9 + 7; 
int n;
int p[N], f[N], s[N];
signed main(){
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	cin >> n;
	F(i, 1, n){
		cin >> p[i];
	}
	f[1] = s[1] = 0;
	F(i, 2, n + 1){
		f[i] = ((s[i - 1] - s[p[i - 1]] + 2) % mod + mod) % mod;
		s[i] = ((s[i - 1] + f[i]) % mod + mod) % mod;
	}
	cout << s[n + 1] << '\n'; 
	return fflush(0), 0; 
}
posted @ 2026-10-03 03:02  superl61  阅读(2)  评论(0)    收藏  举报