题解:洛谷 AT_abc441_b Two Languages
【题目来源】
洛谷:AT_abc441_b [ABC441B] Two Languages - 洛谷
【题目描述】
AtCoder 国家有两种官方语言:高桥乡语和青木乡语。
高桥乡语和青木乡语都使用一些小写英文字母来书写这两种语言中的单词。高桥乡语只使用长度为 \(N\) 的字符串 \(S\) 中包含的字符,而青木乡语只使用长度为 \(M\) 的字符串 \(T\) 中包含的字符。
给你 \(Q\) 个单词 \(w_1,w_2,\ldots,w_Q\),这些单词使用 AtCoder 国家的官方语言。对于每个单词,请根据该单词中包含的字符判断该单词:
- 一定是高桥乡语中的单词
- 一定是青木乡语中的单词
- 无法确定是什么语言中的单词
【输入】
输入内容按如下格式给出:
\(N\) \(M\)
\(S\)
\(T\)
\(Q\)
\(w_1\)
\(w_2\)
\(\vdots\)
\(w_Q\)
【输出】
打印 \(Q\) 行。如果确认 \(w _ i\) 是高桥乡语中的一个词,则 \(i\) 行应包含 Takahashi;如果确认是青木乡语中的一个词,则应包含 Aoki;如果都不能确定,则应包含 Unknown。
【输入样例】
6 5
ahikst
aikot
5
asahi
okita
kiai
hash
it
【输出样例】
Takahashi
Aoki
Unknown
Takahashi
Unknown
【核心思想】
-
问题分析:高桥乡语只使用字符串 \(S\) 中的字符,青木乡语只使用字符串 \(T\) 中的字符。给定 \(Q\) 个单词,判断每个单词:
- 若单词所有字符都在 \(S\) 中且至少有一个不在 \(T\) 中 →
Takahashi - 若单词所有字符都在 \(T\) 中且至少有一个不在 \(S\) 中 →
Aoki - 其他情况(同时在两者中或同时不在两者中)→
Unknown。这是一个字符集合包含判定问题,核心在于判断单词字符集与 \(S\)、\(T\) 字符集的包含关系。
- 若单词所有字符都在 \(S\) 中且至少有一个不在 \(T\) 中 →
-
算法选择:
- 双重遍历判定:对每个单词的每个字符,分别检查是否在 \(S\) 中和是否在 \(T\) 中
- 布尔标记:用
f1标记是否全在 \(S\) 中,f2标记是否全在 \(T\) 中
-
关键步骤:
- 读入数据:\(N, M, S, T, Q\),以及 \(Q\) 个单词
- 处理每个单词 \(w\):
- 初始化
f1 = true, f2 = true - 遍历 \(w\) 的每个字符,检查是否在 \(S\) 中,若有一个不在则
f1 = false - 遍历 \(w\) 的每个字符,检查是否在 \(T\) 中,若有一个不在则
f2 = false - 若
f1 && !f2:输出Takahashi - 若
!f1 && f2:输出Aoki - 否则:输出
Unknown
- 初始化
-
时间/空间复杂度:
- 时间复杂度:\(O(Q \cdot |w| \cdot (|S| + |T|))\),对每个单词的每个字符遍历 \(S\) 和 \(T\)
- 空间复杂度:\(O(1)\),仅使用布尔变量
-
字符集合包含判定的核心思想:
- 集合包含的判定逻辑:"单词一定是高桥乡语" \(\Leftrightarrow\) 单词所有字符 \(\subseteq S\) 且 \(\not\subseteq T\)。即单词能被高桥乡语表示,但不能被青木乡语表示
- 双向验证的必要性:必须同时验证 \(S\) 包含性和 \(T\) 包含性,才能区分"仅属于高桥"、"仅属于青木"、"两者都属于"、"两者都不属于"四种情况
- 朴素遍历的效率:由于字符集为小写英文字母,可用
bool数组或位运算优化到 \(O(1)\) 查询。当前代码采用朴素双重循环,在数据范围较小时可接受 - 提前终止优化:一旦发现某个字符不在目标字符串中,即可将对应标志置
false。代码中已使用break内层循环,但外层循环仍可优化提前退出 - 适用于基础字符串处理、集合包含判定类入门问题
【算法标签】
入门 #字符串入门
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int n, m, q;
string s, t;
int main()
{
// 输入
cin >> n >> m >> s >> t >> q;
// 处理q个查询
while (q--)
{
string w; // 查询字符串
cin >> w;
bool f1 = true; // 标志1:w的所有字符是否都在s中
bool f2 = true; // 标志2:w的所有字符是否都在t中
// 检查w的所有字符是否都在s中
for (int i = 0; i < w.size(); i++)
{
bool flag1 = false; // 标记当前字符是否在s中找到
for (int j = 0; j < s.size(); j++)
{
if (w[i] == s[j]) // 如果字符在s中找到
{
flag1 = true;
break; // 找到就退出内层循环
}
}
if (!flag1) // 如果当前字符不在s中
{
f1 = false; // 整个字符串w不满足条件1
break; // 可以提前退出,但这里没有break,会继续检查后面的字符
}
}
// 检查w的所有字符是否都在t中
for (int i = 0; i < w.size(); i++)
{
bool flag2 = false; // 标记当前字符是否在t中找到
for (int j = 0; j < t.size(); j++)
{
if (w[i] == t[j]) // 如果字符在t中找到
{
flag2 = true;
break; // 找到就退出内层循环
}
}
if (!flag2) // 如果当前字符不在t中
{
f2 = false; // 整个字符串w不满足条件2
break; // 可以提前退出,但这里没有break
}
}
// 根据结果输出
if (f1 == true && f2 == false) // 所有字符都在s中,但至少一个不在t中
{
cout << "Takahashi" << endl;
continue;
}
if (f1 == false && f2 == true) // 所有字符都在t中,但至少一个不在s中
{
cout << "Aoki" << endl;
continue;
}
// 其他情况
cout << "Unknown" << endl;
}
return 0;
}
【运行结果】
6 5
ahikst
aikot
5
asahi
Takahashi
okita
Aoki
kiai
Unknown
hash
Takahashi
it
Unknown
浙公网安备 33010602011771号