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;
}

浙公网安备 33010602011771号