ABC 287 E - Karuta
题目链接:
方法一、\(\rm Trie\)
由于 \(LCP(S_i,S_j)\) 表示两字符串最长公共前缀的长度,首先第一反应就是字典树。
这题比较特殊,需要对每一个字符串求解其对其他所有字符串最长公共前缀的最大值。
思路:先将所有字符串插入字典树中,然后对于每个字符串,忽略字典树里它独有的结点,看看最深可以匹配到多深——这个深度就是答案。
#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
int ch[N][26], cnt[N], idx;
int st[N];//统计经过结点i的字符串是否只有一个
void insert(string s) {
int p = 0;
for (int i = 0; i < s.size(); i++) {
int j = s[i] - 'a';
if (!ch[p][j]) ch[p][j] = ++idx;
else st[ch[p][j]] ++;//说明经过点ch[p][j]的字符串不止一个
p = ch[p][j];
}
}
int query(string s) {
int p = 0, ans = 0;
for (int i = 0; i < s.size(); i++) {
int j = s[i] - 'a';
if (st[ch[p][j]]) ans ++;//如果不止一个就继续搜索
else break;//否则的话说明是该字符串的特有结点,没必要继续搜索,直接break掉
p = ch[p][j];
}
return ans;
}
int main()
{
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
vector<string> S(n);
for (int i = 0; i < n; i++) {
cin >> S[i];
insert(S[i]);
}
for (auto x : S) cout << query(x) << "\n";
return 0;
}
方法二、排序
注意到最大的最长公共前缀一定在字典序上前后两个的字符串之间,因此将这 \(n\) 个字符串按字典序排序,求每个字符串与其相邻的字符串的 \(LCP\),取最大值即可。需要注意的是要保留每个字符串在原序列中的下标。
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
vector<pair<string, int> > S(n);
for (int i = 0; i < n; i++) {
cin >> S[i].first;
S[i].second = i;//记录每个字符串的下标
}
sort(S.begin(), S.end());
auto LCP = [&] (string &l, string &r) {
int t = 0;
while (t < l.size() && t < r.size() && l[t] == r[t]) t++;
return t;
};
vector<int> ans(n);
for (int i = 0; i < n - 1; i++) {
int t = LCP(S[i].first, S[i+1].first);
ans[S[i].second] = max(ans[S[i].second], t);
ans[S[i+1].second] = max(ans[S[i+1].second], t);
}
for (auto i : ans) cout << i << "\n";
return 0;
}
另一种等价的写法:原文请点击这里
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n;
cin >> n;
vector<string> s(n);
for(auto &i : s)
cin >> i;
vector<int> id(n);
iota(id.begin(), id.end(), 0);
sort(id.begin(), id.end(), [&](int x, int y){
return s[x] < s[y];
});
vector<int> ans(n);
auto LCP = [&](string& l, string& r){
int tmp = 0;
while(tmp < l.size() && tmp < r.size() && l[tmp] == r[tmp])
++ tmp;
return tmp;
};
for(int i = 0; i < n - 1; ++ i){
int l = id[i], r = id[i + 1];
int tmp = LCP(s[l], s[r]);
ans[l] = max(ans[l], tmp);
ans[r] = max(ans[r], tmp);
}
for(auto &i : ans)
cout << i << '\n';
return 0;
}

浙公网安备 33010602011771号