A. Did We Get Everything Covered?
https://codeforces.com/problemset/problem/1924/A
题意:使用前k个小写字母组合的所有长度为n的字符串,是否均为s的子序列?如果是输出YES,否则输出NO并找一个不合法的序列输出。
思路:要所有的长度为n的串的组合均为s中出现的子序列,那么对s应该有这个要求:对于每个字符c,每个c的前面和后面的每种其他字符出现的次数的和,都应该至少为n-1次。 这样可以保证对于任意的组合,s中都有足够的字符可以进行子序列的提取。所以只要看s中是否有n个满足条件的区间即可。如果不满足,如何找反例?我们在每个区间中选取一个字符,到了最后条件不满足,说明合法区间数<n,此时只要看看是哪些字符没有出现,造成了无法构成下一个合法的区间,将该字符与前面合法区间的每个区间最后一个位置的字符进行拼接即可。 为什么是每个合法区间的最后一个字符?因为最后一个字符舍弃了前面出现了若干次无用的字符,假如有acccccca...如果我们用aa,那么可以保证长度够短,然后再拼接后面不合法区间的没出现的字符,保证正确。如果用了ac,那么可能在不合法的区间使用之前,构造的字符串已经可以被构造出来了。。有点抽象,但是就是一个贪心的取尾原则
总结:思路应该是,什么样的s,才能让所有的子序列都包含了任意排列的长度为n的包含前k个字符的字符串?
inline void solve() {
int n, k, m;
cin >> n >> k >> m;
string s;
cin >> s;
vector<bool> has(26, false);
int cnt = 0;
string ans;
for (const auto& c : s) {
cnt += !has[c - 'a'];
has[c - 'a'] = true;
if (cnt % k == 0) {
fill(has.begin(), has.end(), false);
ans.push_back(c);
}
}
if (ans.size() >= n) {
cout << "YES\n";
}
else {
cout << "NO\n";
for (int i = 0; i < k; ++i) {
if (!has[i]) {
while (ans.size() < n) {
ans += ('a' + i);
}
break;
}
}
cout << ans << '\n';
}
}

浙公网安备 33010602011771号