Problem Link: usaco.org/index.php?page=viewproblem2&cpid=1231
算法讲解与题解
给定两个字符串 $S$ 和 $T$(只包含 'a'-'r',长度 $\le 10^5$)。
有 $Q$ 个询问($Q \le 10^5$)。
每个询问给出一个字符集(例如 "abc")。我们需要判断:
如果只保留 $S$ 和 $T$ 中属于该字符集的字符,剩下的字符串是否完全相等?
Query: "ac" (保留 a, c)
对于每个 Query,直接模拟构建新字符串并比较。
for(string query_str : queries) {
string s_prime = "", t_prime = "";
for(char c : S) if(in_query(c)) s_prime += c;
for(char c : T) if(in_query(c)) t_prime += c;
if(s_prime == t_prime) print("Y");
else print("N");
}
如何快速判断 $S'$ 和 $T'$ 是否相等?
总对数:$18 \times 18 = 324$ 对。预处理非常快。
Step 1: 预处理 (Preprocessing)
cnt[2][char]。mis[i][j] = true。Step 2: 回答询问 (Query)
mis 表中冲突。
#include <bits/stdc++.h>
using namespace std;
int q, n;
string s, t;
string s0, t0;
// cnt[0] 存 S 的计数,cnt[1] 存 T 的计数
int cnt[2][20];
// mis[i][j] = true 表示字符 i 和 j 发生错位
bool mis[20][20];
int main() {
cin >> s >> t;
// 1. 统计单字符数量
for (char c : s) cnt[0][c-'a']++;
for (char c : t) cnt[1][c-'a']++;
// 2. 预处理所有字符对的错位情况
for (int i = 0; i < 18; i++) {
for (int j = 0; j < 18; j++) {
s0.clear(); t0.clear();
// 只提取 i 和 j 两个字符构建子串
for (char c : s) if (c == 'a'+i || c == 'a'+j) s0 += c;
for (char c : t) if (c == 'a'+i || c == 'a'+j) t0 += c;
if (s0 != t0) mis[i][j] = true;
}
}
cin >> q;
for (int i = 0; i < q; i++) {
string p;
cin >> p;
bool ok = true;
// 检查1: 数量是否一致
for (char c : p)
if (cnt[0][c-'a'] != cnt[1][c-'a']) {
ok = false; break;
}
// 检查2: 两两是否冲突
for (char c : p)
for (char d : p)
if (c != d && mis[c-'a'][d-'a']) { // O(1) 查询
ok = false; break;
}
cout << (ok ? "Y" : "N");
}
return 0;
}
Key Takeaways:
Questions?