Skip to content

Commit 5a0fd6c

Browse files
committed
zz
1 parent c1fa669 commit 5a0fd6c

File tree

3 files changed

+93
-0
lines changed

3 files changed

+93
-0
lines changed

docs/public/st0094-01.jpg

79.2 KB
Loading

docs/public/st0094-02.png

34.3 KB
Loading

docs/smalltalk/st0094.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# 凹语言中文版NOIP 2024真题详解第1题
2+
3+
- 时间:2025-11-12
4+
- 撰稿:凹语言开发组
5+
- 转载请注明原文链接:[https://wa-lang.org/smalltalk/st0094.html](https://wa-lang.org/smalltalk/st0094.html)
6+
7+
---
8+
9+
NOIP 是全国青少年信息学奥林匹克联赛的英文缩写,是面向中小学生的信息学竞赛。由中国计算机学会主办,是国内信息学领域权威的普及性竞赛。主要考察编程能力和算法思维,核心语言包括 C++(主流)、C、Pascal(部分组别)。参赛对象为小学、初中、高中学生,分提高组、普及组等组别。成绩优秀者可获得高校自主招生、综合评价等相关优惠,是信息学特长升学的重要参考。
10+
11+
作为中国乃至面向世界的赛事,NOIP 比赛使用的全部是国外的编程语言。本文尝试通过凹语言来讲解答,通过不同的视角体会算法问题和工程问题的差异。
12+
13+
## 1. NOIP 2024 第1题
14+
15+
![](/st0094-01.jpg)
16+
17+
18+
如果暂时不考虑性能(即 $O(n^2)$ 甚至更慢的复杂度也没关系),我们能找到一个**更直观、更容易理解**的算法,这个算法被称为**最大流/最小费用最大流**模型,或者用更简单的语言描述:**最大二分图匹配**的变形。
19+
20+
但是,因为这个题目的特殊性质(只有 '0' 和 '1' 两种字符,且操作是相邻交换),我们可以避开复杂的图论模型,直接使用**纯粹的贪心和计数**,这是最容易理解且最高效的方法。
21+
22+
## 2. 💡 最易理解的算法:纯粹的贪心与计数
23+
24+
这个算法的思路是:**将问题分解为独立的两部分,并分别用贪心法解决。**
25+
26+
### 2.1. 核心洞察:字符的分类与自由度
27+
28+
所有的字符和位置都可以根据它们能否被交换,被分成四种类型:
29+
30+
| $s_1$ 的状态 ($t_{1,i}$) | $s_2$ 的状态 ($t_{2,i}$) | 位置 $i$ 的自由度 | 决策:匹配 $s_{1,i}$ 和 $s_{2,i}$ |
31+
| :----------------------: | :----------------------: | :----------------: | :-------------------------------: |
32+
| **0 (固定)** | **0 (固定)** | 0 | **固定匹配/不匹配。** $s_{1,i}$ 必须对 $s_{2,i}$。 |
33+
| **0 (固定)** | **1 (可换)** | 1 | $s_{1,i}$ 确定。用 $s_2$ 的**可换字符池**去匹配它。 |
34+
| **1 (可换)** | **0 (固定)** | 1 | $s_{2,i}$ 确定。用 $s_1$ 的**可换字符池**去匹配它。 |
35+
| **1 (可换)** | **1 (可换)** | 2 | **完全自由。** 用 $s_1, s_2$ **剩余**的字符池进行自由组合。 |
36+
37+
### 2.2. 算法核心:两个独立的池子
38+
39+
因为相邻交换的特性(只要没有 $t_{i}=0$ 的障碍物,可换字符可以在其区间内任意排列),我们可以把所有 $t_{1,i}=1$ 的字符**想象成一个大池子 $C_1$**,所有 $t_{2,i}=1$ 的字符**想象成一个大池子 $C_2$**
40+
41+
**目标:** 最大化从 $C_1$ 和 $C_2$ 中取出相同字符进行匹配的次数。
42+
43+
### 2.3. 三步贪心策略
44+
45+
我们将匹配过程分为三步,每一步都采用贪心策略,因为一旦完成了匹配,这个字符就不能再被使用了(即:**先用先得**)。
46+
47+
#### 步骤 1:处理双固定的位置(类型 0)
48+
49+
* **操作:** 遍历所有 $i$,如果 $t_{1,i}=0$ 且 $t_{2,i}=0$。
50+
* **贪心:** 如果 $s_{1,i} = s_{2,i}$,这是一个**确定无疑的匹配**
51+
* **效果:** 答案 $+1$。
52+
53+
#### 步骤 2:处理一固一换的位置(类型 1)
54+
55+
* **操作:** 遍历所有 $i$ 属于类型 1 的位置($t_{1,i} \neq t_{2,i}$)。
56+
* **贪心:** 在这类位置上,我们必须用 $s_1$ 或 $s_2$ 中固定的字符去**锁定**匹配目标,然后**消耗**掉另一个字符串的字符池中的一个对应字符。
57+
* **例:** $t_{1,i}=0, t_{2,i}=1$ 且 $s_{1,i} = '0'$。如果 $C_2$ 池子中还有 '0',我们**必须**用 $C_2$ 中的一个 '0' 来匹配这个固定的 $s_{1,i}$,从而锁定这个匹配。
58+
* **效果:**
59+
* 如果匹配成功,答案 $+1$。
60+
* 相应地,从 $C_1$ 或 $C_2$ 中**减少**对应字符的计数。
61+
62+
**为什么先处理这个?** 因为这些固定字符是**必须**要匹配的(如果可能),它们消耗了 $C_1$ 或 $C_2$ 的资源,限制了接下来的自由组合。
63+
64+
#### 步骤 3:处理双可换的位置(类型 2)
65+
66+
* **操作:** 此时 $C_1$ 和 $C_2$ 池子中还剩下一些字符,以及一些 $t_{1,i}=1, t_{2,i}=1$ 的**空闲位置**
67+
* **贪心:** 由于这些空闲位置是完全自由的,我们可以用 $C_1$ 中**剩余**的字符和 $C_2$ 中**剩余**的字符进行**最大化匹配**
68+
* **匹配 '0':** 我们可以组成 $\min(\text{剩余 '0' in } C_1, \text{剩余 '0' in } C_2)$ 对。
69+
* **匹配 '1':** 我们可以组成 $\min(\text{剩余 '1' in } C_1, \text{剩余 '1' in } C_2)$ 对。
70+
* **效果:** 答案加上这些匹配的总和。
71+
72+
73+
## 3. 开始解决正题
74+
75+
这个算法把一个复杂的排列问题,简化成了**资源分配**问题:
76+
77+
1. **确定**不需要资源的匹配。
78+
2. **贪心**分配资源($C_1$ 和 $C_2$)给那些半固定的需求。
79+
3. **最大化**利用剩余的资源进行自由组合。
80+
81+
由于我们总是在可能的情况下优先匹配(贪心),且我们没有丢失任何字符($C_1$ 和 $C_2$ 中包含了所有可换字符),这个策略是正确的。
82+
83+
凹语言中文编程的代码片段如下:
84+
85+
![](/st0094-02.png)
86+
87+
完整的代码:[https://gitcode.com/wa-lang/wa/blob/master/waroot/examples/noip2024/edit.wz](https://gitcode.com/wa-lang/wa/blob/master/waroot/examples/noip2024/edit.wz)
88+
89+
90+
## 4. 结语:在实战中打磨中文编程
91+
92+
之前我们已经通过凹语言中文编程展示了CSP-J题目的解法,今天我们更进一步给出了NOIP题目的解法。正如我国回归联合国的过程充满了曲折,中文编程想走向世界的道路也注定不会平坦。最终的结果是汉语成了联合国的官方工作语言之一,中文编程也必将在世界上占有一席之地。
93+

0 commit comments

Comments
 (0)