AtCoder Beginner Contest 408 - AtCoder

f

线段树优化 dp

  1. 每个点只能从 $[i-R,i+R]$ 的范围内传播
  2. $dp[i]=dp[pos]+1$,其中 $pos$ 为 $[i-R,i+R]$ 内的满足 $h[pos]\le h[i]-D$ 的最大 $dp[pos]$

所以如何设计 dp 呢

由于状态转移只能单调减,考虑将所有位置 $i$ 按照 $h[i]$ 排序,这样状态只能从前往后传递,这里考虑从小到大排序,如果要计算 $dp[i]$,需要先处理好所有 $h[pos]\le h[i]-D$ 的位置,并将 $dp[pos]$ 填入原位置,之后计算 $[i-R,i+R]$ 的所有 $dp$ 值的最大值 $dp[x]$,状态转移 $dp[i]=dp[x]+1$。这样就满足了两个条件。

单点修改,区间查询,用线段树维护

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#ifdef __LOCAL__
#include "F:/local.h"
#elif __GNUG__
#include <bits/stdc++.h>
#endif

#define fi first
#define se second
using std::cin;
using std::cout;
using std::string;
using PII = std::pair<int, int>;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128;
using u128 = unsigned __int128;
const int INF = 0x3f3f3f3f;
const i64 LINF = 0x3f3f3f3f3f3f3f3f;
const double esp = 1e-7;

template <typename Info>
struct SegmentTree {
int n;
std::vector<Info> info;
SegmentTree() : n(0) {}
SegmentTree(int n_, Info v_ = Info()) {
init(n_, v_);
}
template <typename U>
SegmentTree(std::vector<U> init_) {
init(init_);
}
void init(int n_, Info v_ = Info()) {
init(std::vector(n_, v_));
}
template <typename U>
void init(std::vector<U> init_) {
n = init_.size();
info.assign(4 << std::__lg(n), Info());
auto build = [&](auto && self, int p, int l, int r) {
if (r - l == 1) {
info[p] = init_[l];
return;
}
int m = (l + r) >> 1;
self(self, p << 1, l, m);
self(self, p << 1 | 1, m, r);
pull(p);
};
build(build, 1, 0, n);
}
void pull(int p) {
info[p] = info[p << 1] + info[p << 1 | 1];
}
void modify(int p, int l, int r, int x, const Info &v) {
if (l > x || r <= x) return;
else if (r - l == 1) {
info[p] = v;
} else {
int m = (l + r) >> 1;
modify(p << 1, l, m, x, v);
modify(p << 1 | 1, m, r, x, v);
pull(p);
}
}
void modify(int x, const Info &v) {
modify(1, 0, n, x, v);
}
Info rangeQuery(int p, int l, int r, int x, int y) {
if (l >= x && r <= y) return info[p];
int m = (l + r) >> 1;
if (y <= m) return rangeQuery(p << 1, l, m, x, y);
else if (x >= m) return rangeQuery(p << 1 | 1, m, r, x, y);
else return rangeQuery(p << 1, l, m, x, y) + rangeQuery(p << 1 | 1, m, r, x, y);
}
Info rangeQuery(int l, int r) {
return rangeQuery(1, 0, n, l, r);
}
template <typename F>
int findFirst(int p, int l, int r, int x, int y, F &&pred) {
if (l >= y || r <= x) return -1;
if (l >= x && r <= y && !pred(info[p])) return -1;
if (r - l == 1) return l;
int m = (l + r) >> 1;
int res = findFirst(p << 1, l, m, x, y, pred);
if (res == -1) {
res = findFirst(p << 1 | 1, m, r, x, y, pred);
}
return res;
}
template <typename F>
int findFirst(int l, int r, F &&pred) {
return findFirst(1, 0, n, l, r, pred);
}
template <typename F>
int findLast(int p, int l, int r, int x, int y, F &&pred) {
if (l >= y || r <= x) return -1;
if (l >= x && r <= y && !pred(info[p])) return -1;
if (r - l == 1) return l;
int m = (l + r) >> 1;
int res = findLast(p << 1 | 1, m, r, x, y, pred);
if (res == -1) {
res = findLast(p << 1, l, m, x, y, pred);
}
return res;
}
template <typename F>
int findLast(int l, int r, F &&pred) {
return findLast(1, 0, n, l, r, pred);
}
};

struct Info {
int g = 0;
Info(int g = 0) : g(g) {}
Info operator+(const Info &other) const {
return {std::max(g, other.g)};
}
};
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int N, D, R;
cin >> N >> D >> R;
std::vector<PII> a(N);
SegmentTree<Info> seg(N);
for (int i = 0; i < N; i++) {
cin >> a[i].fi;
a[i].se = i;
}
std::sort(a.begin(), a.end());
int p = 0;
std::vector<int> dp(N, 1);
for (int k = 0; k < N; k++) {
auto [h, i] = a[k];
while (p < N && a[p].fi <= h - D) {
auto [height, id] = a[p];
seg.modify(id, dp[id]);
p++;
}
dp[i] = seg.rangeQuery(i - R, i + R + 1).g + 1;
}
cout << *std::max_element(dp.begin(), dp.end()) - 1 << "\n";
return 0;
}

g

类欧几里得算法

P5179 Fraction - 洛谷

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
i64 solve(i64 a, i64 b, i64 c, i64 d, i64 &p, i64 &q) {
if (a < b && c > d) {
p = 1, q = 1;
} else {
solve(d % c, c, b - (d / c) * a, a, q, p);
q += (d / c) * p;
}
return q;
}
void solve() {
i64 a, b, c, d;
cin >> a >> b >> c >> d;
i64 p, q;
cout << solve(a, b, c, d, p, q) << "\n";
}