思路:
-  
二分查找:
-  
left = 1(最小可能距离),right = L(最大可能距离)。 -  
每次取
mid = (left + right) / 2,判断是否可以通过增设 ≤K个路标使得所有相邻路标的距离 ≤mid。 
 -  
 -  
贪心验证:
-  
遍历所有相邻原始路标,计算它们之间的
gap。 -  
对于每个
gap,计算需要插入的路标数(gap - 1) / mid。 -  
如果总增设数
required ≤ K,则mid可行,尝试更小的mid;否则尝试更大的mid。 
 -  
 -  
输出答案:
-  
最终
ans即为最小的“空旷指数”。 
 -  
 
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;int main() {int L, N, K;cin >> L >> N >> K;vector<int> markers(N);for (int i = 0; i < N; i++) {cin >> markers[i];}int left = 1;  // 最小可能距离int right = L;  // 最大可能距离int ans = L;// 二分查找最小的“空旷指数”while (left <= right) {int mid = (left + right) / 2;int required = 0;  // 需要增设的路标数量// 计算需要增设多少路标才能让所有间隔 ≤ midfor (int i = 1; i < N; i++) {int gap = markers[i] - markers[i - 1];required += (gap - 1) / mid;}if (required <= K) {ans = mid;right = mid - 1;  // 尝试更小的“空旷指数”} else {left = mid + 1;  // 需要更大的“空旷指数”}}cout << ans << endl;return 0;
} 
 
  
思路:
-  
backtrack函数:这是递归回溯的核心函数。
-  
:
n是目标美味程度,current是当前配料组合,sum是当前组合的总和,index是当前处理的配料索引。 -  
当处理完所有10个配料(
index == 10),检查总和是否等于n,如果是,则保存当前组合。 -  
对于当前配料,尝试1、2、3克,递归处理下一个配料。通过剪枝条件提前终止无效的递归路径。
 
 -  
 
#include <iostream>
#include <vector>
using namespace std;vector<vector<int>> solutions;  // 存储所有解决方案void backtrack(int n, vector<int>& current, int sum, int index) {if (index == 10) {if (sum == n) {solutions.push_back(current);}return;}// 尝试1、2、3克for (int i = 1; i <= 3; ++i) {if (sum + i > n) continue;  // 剪枝:总和超过n,跳过// 剩下的配料即使全选1克也无法达到n,剪枝if (sum + i + (10 - index - 1) > n) continue;current[index] = i;backtrack(n, current, sum + i, index + 1);}
}int main() {int n;cin >> n;vector<int> current(10);  // 当前组合backtrack(n, current, 0, 0);cout << solutions.size() << endl;for (const auto& sol : solutions) {for (int i = 0; i < 10; ++i) {cout << sol[i] << " ";}cout << endl;}return 0;
} 
 
正则表达式
基本概念
- 字符组:用方括号 
[]表示,用于匹配方括号内的任意一个字符。例如,[abc]可以匹配a、b或c中的任意一个字符。 - 量词:用于指定前面的字符或字符组出现的次数。常见的量词有 
*(零次或多次)、+(一次或多次)、?(零次或一次)、{n}(恰好n次)、{n,}(至少n次)、{n,m}(n到m次)。例如,a*表示匹配零个或多个a,a{2,4}表示匹配2到4个a。 - 元字符:具有特殊含义的字符,如 
^表示匹配字符串的开头,$表示匹配字符串的结尾,.表示匹配除换行符以外的任意一个字符。例如,^a表示以a开头的字符串,a$表示以a结尾的字符串。 - 转义字符:用反斜杠 
\表示,用于转义元字符,使其失去特殊含义,而表示其本身。例如,\.表示匹配字符.,\\表示匹配字符\。 
常用操作
- 匹配:使用正则表达式来检查一个字符串是否符合特定的模式。例如,判断一个字符串是否是有效的电子邮件地址,可以使用正则表达式 
^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$。 - 查找:在一个字符串中查找符合正则表达式模式的子串。例如,在一篇文章中查找所有的电话号码,可以使用正则表达式 
\d{3}-\d{8}|\d{4}-\d{7}。 - 替换:将匹配到的字符串替换为指定的内容。例如,将字符串中的所有数字替换为 
*,可以使用正则表达式\d和替换字符串*。 - 分割:根据正则表达式的模式将字符串分割成多个子串。例如,将一个逗号分隔的字符串分割成数组,可以使用正则表达式 
,。 
示例
- 匹配手机号码:
^1[3-9]\d{9}$。这个正则表达式表示以1开头,第二位是3到9中的任意一个数字,后面跟着9个数字。 - 匹配身份证号码:
^\d{17}[\dXx]$。表示由17位数字和最后一位数字或X(或x)组成。
 
| 元字符 | 说明 | |
|---|---|---|
. | 匹配任意单个字符(除换行符 \n) | |
^ | 匹配字符串的开头 | |
$ | 匹配字符串的结尾 | |
* | 匹配前面的字符0次或多次 | |
+ | 匹配前面的字符1次或多次 | |
? | 匹配前面的字符0次或1次 | |
{n} | 匹配前面的字符恰好n次 | |
{n,} | 匹配前面的字符至少n次 | |
{n,m} | 匹配前面的字符n到m次 | |
[...] | 匹配括号内的任意一个字符(字符类) | |
[^...] | 匹配不在括号内的任意字符 | |
| ` | ` | 或(匹配左边或右边的模式) | 
\d | 匹配数字(等价于 [0-9]) | |
\D | 匹配非数字(等价于 [^0-9]) | |
\w | 匹配字母、数字、下划线(等价于 [a-zA-Z0-9_]) | |
\W | 匹配非字母、数字、下划线 | |
\s | 匹配空白字符(空格、制表符、换行符等) | |
\S | 匹配非空白字符 | |
\b | 匹配单词边界 | |
\B | 匹配非单词边界 | 
3. 正则表达式示例
(1) 匹配数字
| 正则表达式 | 说明 | 匹配示例 | 
|---|---|---|
\d+ | 匹配1个或多个数字 | 123, 0, 456 | 
\d{3} | 匹配3位数字 | 123, 456 | 
\d{2,4} | 匹配2~4位数字 | 12, 123, 1234 |