Skip to content

Commit fb2774a

Browse files
committed
add abc390
1 parent cf4a9ad commit fb2774a

File tree

3 files changed

+333
-0
lines changed

3 files changed

+333
-0
lines changed

docs/algorithm/AtCoder/abc390.md

Lines changed: 331 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,331 @@
1+
## [A - 12435](https://atcoder.jp/contests/abc390/tasks/abc390_a)
2+
3+
???+ Abstract "题目大意"
4+
5+
给你一个 $1$ 到 $5$ 的排列,能否通过一次交换相邻的两个数字的操作使得这个排列有序?
6+
7+
??? Success "参考代码"
8+
9+
=== "C++"
10+
11+
```c++
12+
#include <iostream>
13+
#include <vector>
14+
15+
using namespace std;
16+
17+
int main()
18+
{
19+
vector<int> a(5), target = {1, 2, 3, 4, 5};
20+
for (auto &x : a)
21+
cin >> x;
22+
for (int i = 0; i < 4; i++)
23+
if (a[i] > a[i + 1])
24+
{
25+
swap(a[i], a[i + 1]);
26+
if (a == target)
27+
{
28+
cout << "Yes" << endl;
29+
return 0;
30+
}
31+
break;
32+
}
33+
cout << "No" << endl;
34+
return 0;
35+
}
36+
```
37+
38+
---
39+
40+
## [B - Geometric Sequence](https://atcoder.jp/contests/abc390/tasks/abc390_b)
41+
42+
???+ Abstract "题目大意"
43+
44+
给你一个长度为 $N$ 的数列 $A$,判断 $A$ 是不是一个等比数列。
45+
46+
??? Success "参考代码"
47+
48+
=== "C++"
49+
50+
```c++
51+
#include <iostream>
52+
#include <vector>
53+
54+
using namespace std;
55+
using LL = long long;
56+
57+
int main()
58+
{
59+
int n;
60+
cin >> n;
61+
vector<LL> a(n);
62+
for (auto &x : a)
63+
cin >> x;
64+
65+
for (int i = 2; i < n; i++)
66+
if (a[i] * a[0] != a[i-1] * a[1])
67+
{
68+
cout << "No" << endl;
69+
return 0;
70+
}
71+
cout << "Yes" << endl;
72+
return 0;
73+
}
74+
```
75+
76+
---
77+
78+
## [C - Paint to make a rectangle](https://atcoder.jp/contests/abc390/tasks/abc390_c)
79+
80+
???+ Abstract "题目大意"
81+
82+
有一个 $H \times W(1 \le H, W \le 1000)$ 的网格,每个格子可能是 `#`(黑色)、`.`(白色)或 `?`(未涂色)。你可以将 `?` 涂成黑色或者白色。问:是否存在一种涂色的方案,使得所有黑色格子形成一个长方形?
83+
84+
??? Note "解题思路"
85+
86+
记录下所有黑色格子的横纵坐标的最大最小值,就可以确定长方形的左上角和右下角,然后判断里面有没有白色格子就好。
87+
88+
??? Success "参考代码"
89+
90+
=== "C++"
91+
92+
```c++
93+
#include <iostream>
94+
#include <limits>
95+
#include <string>
96+
#include <vector>
97+
98+
using namespace std;
99+
100+
const int PINF = numeric_limits<int>::max();
101+
const int NINF = numeric_limits<int>::min();
102+
103+
int main()
104+
{
105+
int h, w;
106+
cin >> h >> w;
107+
vector<string> g(h);
108+
int r1 = PINF, c1 = PINF;
109+
int r2 = NINF, c2 = NINF;
110+
for (int r = 0; r < h; r++)
111+
{
112+
cin >> g[r];
113+
for (int c = 0; c < w; c++)
114+
if (g[r][c] == '#')
115+
{
116+
r1 = min(r1, r);
117+
c1 = min(c1, c);
118+
r2 = max(r2, r);
119+
c2 = max(c2, c);
120+
}
121+
}
122+
for (int r = r1; r <= r2; r++)
123+
for (int c = c1; c <= c2; c++)
124+
if (g[r][c] == '.')
125+
{
126+
cout << "No" << endl;
127+
return 0;
128+
}
129+
cout << "Yes" << endl;
130+
return 0;
131+
}
132+
```
133+
134+
---
135+
136+
## [D - Stone XOR](https://atcoder.jp/contests/abc390/tasks/abc390_d)
137+
138+
???+ Abstract "题目大意"
139+
140+
有 $N(2 \le N \le 12)$ 个袋子,第 $i$ 个袋子有 $A_i(1 \le A_i \le 10 ^ {17})$ 个石头。你可以执行以下操作任意次:
141+
142+
- 选择两个袋子,将其中一个袋子的所有石头移动到另一个袋子中。
143+
144+
在你执行完所有操作后,设第 $i$ 个袋子最终还有 $B_i$ 个石头,且 $X = B_1 \oplus B_2 \oplus \cdots \oplus B_N$,问:有多少种不同的 $X$ 值?
145+
146+
??? Note "解题思路"
147+
148+
可以通过搜索实现,问题相当于将 $N$ 个数字划分成若干个即可,这其实就是贝尔数的枚举方式,每个数字要么加入之前已有的集合中,要么单开一个新的集合。
149+
150+
??? Success "参考代码"
151+
152+
=== "C++"
153+
154+
```c++
155+
#include <iostream>
156+
#include <unordered_set>
157+
#include <vector>
158+
159+
using namespace std;
160+
using LL = long long;
161+
162+
int main()
163+
{
164+
int n;
165+
cin >> n;
166+
vector<LL> a(n), b(n);
167+
for(auto &x : a)
168+
cin >> x;
169+
unordered_set<LL> vis;
170+
171+
auto dfs = [n, &a, &b, &vis](auto &self, int cur, int m) -> void
172+
{
173+
if(cur == n)
174+
{
175+
LL num = 0;
176+
for(auto s : b)
177+
num ^= s;
178+
vis.insert(num);
179+
return;
180+
}
181+
182+
for(int i = 0; i < m; i++)
183+
{
184+
b[i] += a[cur];
185+
self(self, cur + 1, m);
186+
b[i] -= a[cur];
187+
}
188+
b[m] = a[cur];
189+
self(self, cur + 1, m + 1);
190+
b[m] = 0;
191+
};
192+
193+
dfs(dfs, 0, 0);
194+
cout << vis.size() << endl;
195+
return 0;
196+
}
197+
```
198+
199+
---
200+
201+
## [E - Vitamin Balance](https://atcoder.jp/contests/abc390/tasks/abc390_e)
202+
203+
???+ Abstract "题目大意"
204+
205+
有 $N(1 \le N \le 5000)$ 种食物,有三种维生素类型 $1$、$2$ 或 $3$,吃下第 $i$ 种食物的提供 $A_i(1 \le A_i \le 2 \times 10^5)$ 单位的维生素 $V_i(V_i \in \{1, 2, 3\})$,以及 $C_i$ 单位的卡路里。
206+
207+
你可以选择吃任意食物,但摄入的卡路里总量不能超过 $X(1 \le C_i \le X \le 5000)$。
208+
209+
问:维生素 $1$、$2$、$3$ 中摄入量最少的那种维生素的摄入量的最大值是多少?
210+
211+
??? Note "解题思路"
212+
213+
可以轻易的用背包处理出 $dp[1][i]$、$dp[2][i]$、$dp[3][i]$ 表示在摄入 $i$ 卡路里的情况下最多能获得多少维生素 $1$、$2$、$3$。这一块时间复杂度是 $O(NX)$
214+
215+
然后可以同样用背包,把 $dp[1][i]$ 和 $dp[2][i]$ 组合成摄入 $i$ 卡路里能能获得前两种维生素中的最小值的最大值,再继续混合成三种的就好。这一块时间复杂度是 $O(X^2)$
216+
217+
??? Success "参考代码"
218+
219+
=== "C++"
220+
221+
```c++
222+
#include <iostream>
223+
#include <vector>
224+
225+
using namespace std;
226+
227+
int main()
228+
{
229+
int n, x;
230+
cin >> n >> x;
231+
vector<vector<int>> a(3), c(3);
232+
for (int i = 0; i < n; i++)
233+
{
234+
int v, aa, cc;
235+
cin >> v >> aa >> cc;
236+
v--;
237+
a[v].push_back(aa);
238+
c[v].push_back(cc);
239+
}
240+
241+
auto DP = [x](const vector<int> &a, const vector<int> &c) -> vector<int>
242+
{
243+
int n = a.size();
244+
vector<int> dp(x + 1);
245+
for (int i = 0; i < n; i++)
246+
for (int j = x; j >= c[i]; j--)
247+
dp[j] = max(dp[j], dp[j - c[i]] + a[i]);
248+
return dp;
249+
};
250+
251+
vector<int> f = DP(a[0], c[0]);
252+
253+
auto mix = [x, DP, &f](const vector<int> &a, const vector<int> &c) -> vector<int>
254+
{
255+
vector<int> g = DP(a, c);
256+
vector<int> h(x + 1);
257+
for (int i = 0; i <= x; i++)
258+
for (int j = 0; i + j <= x; j++)
259+
h[i + j] = max(h[i + j], min(f[i], g[j]));
260+
return h;
261+
};
262+
263+
f = mix(a[1], c[1]);
264+
f = mix(a[2], c[2]);
265+
cout << f[x] << endl;
266+
return 0;
267+
}
268+
```
269+
270+
---
271+
272+
## [F - Double Sum 3](https://atcoder.jp/contests/abc390/tasks/abc390_f)
273+
274+
???+ Abstract "题目大意"
275+
276+
给你一个长度为 $N(1 \le N \le 3 \times 10 ^ 5)$ 的整数序列 $A = (A_1, A_2, \cdots, A_N)$,其中 $1 \le A_i \le N$。
277+
278+
对于一个满足 $1 \le L \le R \le N$ 的数对 $(L, R)$,定义 $F(L, R)$ 的值如下:
279+
280+
- 首先,在黑板中写下 $A_L, A_{L+1}, ..., A_R$ 这些数字。
281+
- 重复以下操作直到黑板中所有的数字都被擦除:
282+
- 选择两个整数 $l$,$r$,需满足黑板上所有 $[l, r]$ 范围内的整数至少各出现一次。随后擦除黑板上所有 $[l, r]$ 范围内的整数。
283+
- $F(L, R)$ 定义为清除所有整数所需的最小操作次数。
284+
285+
求出 $\sum\limits_{L=1}^N\sum\limits_{R=L}^N f(L, R)$
286+
287+
??? Note "解题思路"
288+
289+
问题相当于将一堆数字划分成尽可能少的连续整数段。不妨钦定一个连续整数段中最大的数字作为代表,同时如果有多个元素,选取最靠左的作为代表。
290+
291+
对于一个数字 $l \le i \le r$,数字 $A_i$ 如果是元素,则 $A_l, ...A_{i-1}$ 中一定没有 $A_i + 1$ 或者 $A_i$,且 $A_{i+1}, ...A_r$ 中一定没有 $A_i + 1$。因此,预处理出两个数组 $pre[i]$ 表示在 $i$ 的左边且第一个等于 $A_i + 1$ 或 $A_i$ 的位置,$nxt[i]$ 表示在 $i$ 的右边且第一个等于 $A_i + 1$ 的位置。这样 $A_i$ 的贡献就是 $(i - pre[i]) \times (nxt[i]-i)$
292+
293+
??? Success "参考代码"
294+
295+
=== "C++"
296+
297+
```c++
298+
#include <iostream>
299+
#include <vector>
300+
301+
using namespace std;
302+
using LL = long long;
303+
304+
int main()
305+
{
306+
int n;
307+
cin >> n;
308+
vector<int> a(n);
309+
for(auto &x : a)
310+
cin >> x;
311+
vector<int> pre(n), pos(n+2, -1);
312+
for(int i = 0; i < n; i++)
313+
{
314+
int x = a[i];
315+
pre[i] = max(pos[x], pos[x+1]);
316+
pos[x] = i;
317+
}
318+
pos.assign(n+2, n);
319+
LL ans = 0;
320+
for(int i = n - 1; i >= 0; i--)
321+
{
322+
int x = a[i];
323+
ans += (LL)(i - pre[i]) * (pos[x+1] - i);
324+
pos[x] = i;
325+
}
326+
cout << ans << endl;
327+
return 0;
328+
}
329+
```
330+
331+
---

docs/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
1111
最近更新:
1212

13+
- (20250614) [ABC390(A-F) 题解](./algorithm/AtCoder/abc390.md)
1314
- (20250606) [ABC389(A-F) 题解](./algorithm/AtCoder/abc389.md)
1415
- (20250601) [ABC388(A-G) 题解](./algorithm/AtCoder/abc388.md)
1516
- (20250521) [System R 优化器框架精读](./dev/db/optimizer/System_R/SystemR.md)

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ nav:
99
- 算法:
1010
- algorithm/index.md
1111
- AtCoder:
12+
- ABC390(A-F): algorithm/AtCoder/abc390.md
1213
- ABC389(A-F): algorithm/AtCoder/abc389.md
1314
- ABC388(A-G): algorithm/AtCoder/abc388.md
1415
- ABC386(A-F): algorithm/AtCoder/abc386.md

0 commit comments

Comments
 (0)