【洛谷】P10417 [蓝桥杯 2023 国 A] 第 K 小的和 的题解

【洛谷】P10417 [蓝桥杯 2023 国 A] 第 K 小的和 的题解

题目传送门

题解

CSP-S1 补全程序,致敬全 A 的答案,和神奇的预言家。

写一下这篇的题解说不定能加 CSP 2024 的 RP

首先看到 k k k 这么大的一个常数,就想到了二分。然后写一个判断的函数:枚举 A A A 序列里面的数,然后再找 B B B 序列能和 A A A 序列里选出来的数加起来之和小于等于 t t t 即可。

但是,这样的话可能会超时,所以,我们把 B B B 序列的循环改成二分,注意要二分必须在有序的情况下,所以提前排序。时间复杂度 O ( n log ⁡ m ) O(n \log m) O(nlogm)

不开 long long 见祖宗!!!

代码

#include <bits/stdc++.h>
#define lowbit(x) x & (-x)
#define endl "\n"
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define int long long
namespace fastIO {
	inline int read() {
		register int x = 0, f = 1;
		register char c = getchar();
		while (c < '0' || c > '9') {
			if(c == '-') f = -1;
			c = getchar();
		}
		while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
		return x * f;
	}
	inline void write(int x) {
		if(x < 0) putchar('-'), x = -x;
		if(x > 9) write(x / 10);
		putchar(x % 10 + '0');
		return;
	}
}
using namespace fastIO;
int n, m, k, a[100005], b[100005]; 
bool check (int x) {
	int res = 0;
	for (int i = 1; i <= n; i++) {
		res += upper_bound (b + 1, b + m + 1, x - a[i]) - b - 1;
	}
	return res >= k;
}
signed main() {
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	n = read(), m = read(), k = read();
	for(int i = 1; i <= n; i ++) {
		a[i] = read();
	}
	for(int i = 1; i <= m; i ++) {
		b[i] = read();
	}
	sort(b + 1, b + m + 1);
	int l = 0, r = INT_MAX;
	while (l < r) {
		int mid = (l + r) >> 1;
		if (check (mid)) {
			r = mid;
		}
		else l = mid + 1;
	}
	write(l);
	return 0;
}
<think>嗯,我需要解决洛谷P10992题目对应的蓝桥杯2023赛Python组的最长同类子串问题。首先,我得理解题目要求。根据题目名称,“最长同类子串”应该是指在一个字符串中找到最长的连续子串,其中所有字符都属于同一类别。这里的“同类”可能有不同的定义,比如相同的字符,或者是同一类别的字符,比如数字、字母等。不过根据常见的类似题目,通常是指字符完全相同的情况,例如最长连续相同字符子串。不过可能需要根据题目具体描述来确定,但现在假设是找最长的连续相同字符的子串。 接下来,我需要回忆类似的问题解决方法。例如,最长连续递增子串或者最长重复子串。对于最长连续相同字符的问题,通常可以通过一次遍历来实现。具体来说,可以维护一个当前字符的计数,当遇到不同字符时重置计数,并记录最大值。这种方法的时间复杂度是O(n),非常高效。 不过,用户提到的“同类子串”可能不仅仅是相同的字符,可能有其他定义。比如,题目可能将字符分类为数字、字母、大写、小写等,要求子串中的字符都属于同一类别。这种情况下,需要判断每个字符所属的类别,并在遍历时跟踪当前类别,如果类别变化则重置计数。 假设题目中的“同类”是指字符完全相同,那么解决方法是比较直接的。例如,对于字符串“aaabbbbaac”,最长同类子串是“bbbb”,长度为4。实现方法可以是遍历字符串,比较当前字符与前一个字符,如果相同则增加计数器,否则重置计数器为1,同时不断更新最大长度。 但是,如果“同类”有不同的定义,比如同一类别的字符,比如所有字母,不管大小写,或者所有数字,那么需要调整判断条件。例如,判断字符是否为同一类别,可以使用Python中的内置方法,如isalpha(), isdigit()等。例如,字符串“aAabB123”中的最长同类子串可能是“aAabB”(如果类别是字母),或者是“123”(数字),具体取决于题目要求。 由于用户提到的是蓝桥杯2023赛Python组的题目,我需要查找是否有相关的题解或参考代码。根据提供的引用内容,引用[3]提到了最大公共子串的问题,这可能与子串问题相关,但题目不同。引用[4]中的代码可能涉及数学计算,但可能与当前问题无关。 因此,可能需要根据常规算法来设计解决方案。首先明确题目中的“同类子串”定义。假设题目中的同类子串是指所有字符相同的情况,那么可以采用如下步骤: 1. 初始化max_lengthcurrent_length为1,因为至少每个字符本身长度为1。 2. 遍历字符串从第二个字符开始,比较当前字符与前一个字符。 3. 如果相同,current_length加1,并更新max_length。 4. 如果不同,重置current_length为1。 5. 遍历结束后,max_length即为最长同类子串的长度。 例如,字符串“aaabbbbaac”的处理过程: - 索引1(第二个a):current_length=2,max=2 - 索引2(第三个a):current_length=3,max=3 - 索引3(第一个b):不同,current_length重置为1,max保持3 - 依次类推,直到结束,得到最大长度4。 如果题目中的同类子串有不同的定义,比如允许同一类别(如数字、字母),则需要修改判断条件。例如,判断当前字符与前一个字符是否属于同一类别: def is_same_category(c1, c2): # 假设同类定义为都是数字或都是字母(不分大小写) return (c1.isdigit() and c2.isdigit()) or (c1.isalpha() and c2.isalpha()) 然后,在遍历时使用这个函数来判断是否属于同类。 但根据题目名称“最长同类子串”,可能更倾向于所有字符相同的情况,因此先按这种情况处理。 接下来,考虑代码实现。例如: def longest_homogeneous_substring(s): if not s: return 0 max_len = 1 current_len = 1 for i in range(1, len(s)): if s[i] == s[i-1]: current_len += 1 max_len = max(max_len, current_len) else: current_len = 1 return max_len 测试用例:如输入“aaabbbbaac”,返回4。输入“abc”,返回1。输入“”,返回0。 但根据蓝桥杯的题目,可能需要输出子串本身,而不仅仅是长度。因此,需要记录最大长度时的起始位置或结束位置,以便提取子串。 改进后的代码: def longest_homogeneous_substring(s): if not s: return 0, "" max_len = 1 current_len = 1 start = 0 max_start = 0 for i in range(1, len(s)): if s[i] == s[i-1]: current_len += 1 if current_len > max_len: max_len = current_len max_start = start else: current_len = 1 start = i return max_len, s[max_start:max_start+max_len] 这里,start记录当前子串的起始位置,当字符变化时,start更新为当前i的位置。例如,字符串“aaabbbbaac”的处理中,当遇到第一个b时,start变为3,current_len重置为1。当连续四个b时,current_len增加到4,max_len更新为4,max_start为3,对应的子串是“bbbb”。 但这样处理是否正确呢?例如,当字符连续相同时,start一直保持初始位置。例如,字符串“aaa”中,start始终是0。当i=1,current_len=2,max_start=0;i=2,current_len=3,max_start=0。正确。 但上面的代码中,当字符变化时,start被设置为i,也就是新的子串的起始位置。例如,原字符串是“aabbb”: 索引0:a,初始start=0 索引1:a,current_len=2,max_len=2,start保持0 索引2:b,字符变化,current_len重置为1,start=2 索引3:b,current_len=2,max_len=2,max_start=2 索引4:b,current_len=3,max_len=3,max_start=2 最终返回长度为3,子串“bbb” 是正确的。 但需要测试其他情况,比如当最大子串出现在末尾时。例如字符串“abbb”:处理到最后i=3时,current_len=3,max_start=1,子串“bbb”。 所以,这段代码似乎可以正确记录最长子串的位置长度。 因此,用户需要的是这样的代码,或者可能题目有其他要求。例如,题目可能要求输出所有最长子串中的第一个或最后一个,或者需要处理多个相同长度的情况。 但根据常规题目要求,通常是输出最长的长度,或者其中一个最长的子串。 如果题目需要输出所有最长的子串,那么需要记录所有可能的起始位置,或者收集所有可能的子串。但蓝桥杯的题目通常只需要输出长度或者其中任意一个。 现在,需要确认题目的具体要求。由于用户提到的是洛谷P10992,但可能无法直接访问该题目,因此可能需要根据用户提供的引用或常见题型推断。 查看提供的引用,引用[3]中的代码是寻找最大公共子串,这与当前问题不同,但可能相关的是子串的处理方法。例如,遍历两个字符串,寻找最长的公共部分。但当前问题可能更简单,只需在一个字符串中找到最长的连续相同字符的子串。 假设题目要求的是最长连续相同字符子串,那么上述代码即可解决问题。例如,对于输入字符串“aaabbbbaac”,输出长度4,子串“bbbb”。 但用户提到的是“同类子串”,可能题目中的定义不同。例如,可能将字符分为不同的类别,如数字、大写字母、小写字母等,同一类别的字符组成的子串称为同类子串。例如,字符串“aA123”,其中“aA”属于同一类别(字母),而“123”是数字。此时,最长同类子串是“aA”或“123”,长度分别为23。 此时,算法需要判断每个字符的类别,并跟踪当前类别,当类别变化时重置计数器。 例如,定义一个函数判断两个字符是否属于同一类别: def same_class(c1, c2): # 定义同类:例如,数字、大写字母、小写字母各为一类 if c1.isdigit(): return c2.isdigit() elif c1.isupper(): return c2.isupper() elif c1.islower(): return c2.islower() else: return False # 其他字符各自为一类 然后,在遍历字符串时,比较当前字符与前一个是否属于同一类: def longest_homogeneous_substring(s): if not s: return 0, "" max_len = 1 current_len = 1 start = 0 max_start = 0 for i in range(1, len(s)): if same_class(s[i], s[i-1]): current_len += 1 if current_len > max_len: max_len = current_len max_start = start else: current_len = 1 start = i return max_len, s[max_start:max_start+max_len] 但这里的same_class函数需要根据题目具体定义来调整。比如,题目可能将所有字母视为同一类,不分大小写,或者将数字、字母分开。例如,同类可能定义为同一类型(数字、字母、其他),或者更细的分类。 假设题目中的同类子串是同一字符,那么回到原来的解法。否则,需要根据题目具体要求调整判断条件。 由于用户提到的是蓝桥杯2023赛Python组的题目,可能需要参考已有的题解。但提供的引用中没有直接相关的代码。引用[3]是关于最大公共子串,可能使用滑动窗口或动态规划,但问题不同。 因此,回到问题本身,假设题目要求的是最长连续相同字符的子串,那么代码实现如之前所述。 但用户可能遇到更复杂的情况,例如,同类子串允许字符属于同一类别,如所有数字,或者所有字母,或者所有大写字母等。因此,需要明确题目的定义。 如果题目中的同类子串是指所有字符相同,那么上述第一种方法即可。如果题目有其他定义,则需要调整判断条件。 例如,如果同类子串定义为所有字符属于同一类型(数字、字母、其他),则: def get_class(c): if c.isdigit(): return 'digit' elif c.isalpha(): return 'alpha' else: return 'other' 然后在遍历时,比较当前字符前一个字符的类别是否相同: current_class = get_class(s[0]) current_len = 1 max_len = 1 ... 每次迭代时检查当前字符的类别是否与current_class相同,如果是则增加current_len,否则重置。 这种情况下,代码需要处理每个字符的类别。 假设题目中的同类子串是字符完全相同,那么以下代码即可解决问题: def longest_homogeneous_substring(s): n = len(s) if n == 0: return 0 max_len = 1 current_len = 1 for i in range(1, n): if s[i] == s[i-1]: current_len += 1 max_len = max(max_len, current_len) else: current_len = 1 return max_len 但题目可能需要输出子串本身,而不仅仅是长度。例如,返回最长子串的长度及其内容。此时,代码需要记录起始位置: def longest_homogeneous_substring(s): n = len(s) if n == 0: return 0, "" max_len = 1 current_len = 1 start = 0 max_start = 0 for i in range(1, n): if s[i] == s[i-1]: current_len += 1 if current_len > max_len: max_len = current_len max_start = start else: current_len = 1 start = i return max_len, s[max_start:max_start+max_len] 测试这个函数: print(longest_homogeneous_substring("aaabbbbaac")) # (4, 'bbbb') print(longest_homogeneous_substring("abc")) # (1, 'a') print(longest_homogeneous_substring("a")) # (1, 'a') print(longest_homogeneous_substring("abba")) # (2, 'bb') 现在,需要考虑蓝桥杯的题目是否有其他要求,比如时间复杂度或空间复杂度限制。由于字符串长度可能很大,O(n)的时间复杂度是可行的。 如果题目中的输入规模较大,比如1e6字符,Python的这种解法是可以通过的。 总结,解决该问题的步骤是: 1. 确定“同类子串”的定义(字符相同或类别相同)。 2. 遍历字符串,维护当前子串的长度起始位置。 3. 比较当前字符与前一个字符是否符合同类条件。 4. 更新最大长度对应的起始位置。 5. 遍历结束后返回结果。 根据用户提供的引用,引用[3]中的代码用于寻找两个字符串的最大公共子串,但当前问题不同,因此不能直接使用。但可以借鉴遍历字符串的方法。 因此,最终的Python代码实现应该如上述所示,根据题目具体要求调整同类判断的条件。</think>### 最长同类子串问题解答 根据题目要求,我们需要在给定字符串中找出最长的连续同类字符子串。假设题目中“同类”定义为字符完全相同,解决方案如下: #### 算法思路 1. **初始化变量**:记录当前连续子串长度`current_len`最大长度`max_len`,起始位置`start`最长子串起始位置`max_start` 2. **遍历字符串**:从第二个字符开始,比较当前字符与前一个字符 3. **更新计数器**:若字符相同则增加当前长度,否则重置计数器并更新起始位置 4. **记录最大值**:始终维护最长子串长度起始位置 5. **返回结果**:根据记录的位置提取最长子串 #### 代码实现 ```python def longest_homogeneous_substring(s): if not s: return 0, "" max_len = 1 current_len = 1 start = 0 max_start = 0 for i in range(1, len(s)): if s[i] == s[i-1]: current_len += 1 if current_len > max_len: max_len = current_len max_start = start else: current_len = 1 start = i return max_len, s[max_start:max_start+max_len] # 测试样例 print(longest_homogeneous_substring("aaabbbbaac")) # (4, 'bbbb') print(longest_homogeneous_substring("abc")) # (1, 'a') print(longest_homogeneous_substring("abba")) # (2, 'bb') ``` #### 复杂度分析 - **时间复杂度**:$O(n)$,仅需一次线性遍历 - **空间复杂度**:$O(1)$,仅使用常数级额外空间 #### 扩展说明 若题目中“同类”定义为其他规则(如数字/字母分类),只需修改字符比较逻辑即可。例如判断字符类别是否相同: ```python def is_same_category(c1, c2): return (c1.isdigit() and c2.isdigit()) or (c1.isalpha() and c2.isalpha()) ``` 将代码中的字符相等判断`==`替换为此函数即可实现分类统计[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值