#贪心 ## 题目大意 给定一个循环节 $s$,求给定的字符距离它右边最近的 $\texttt{g}$ 的距离,求最大值。 ## 思路 贪心,我们可以先思考没有循环。我们首先从前往后慢慢扫描,如果字符符合要求,我们就记录下这个字符的位置。这里我们只用记录**最小值**。 如果我们遇到了字符 $\texttt{g}$,那么直接记录答案,并且分节,因为这里是求最近的字符 $\texttt{g}$。 现在考虑循环。我们知道,相同的循环节如果我们直接记录,那么可能会存在跨过循环节的现象。但是我们知道,如果一个循环节里面有 $\texttt{g}$,那么不会存在两个循环节都找不到答案的情况;如果没有 $\texttt{g}$,则无解。我们只需将字符串拷贝一遍即可。 ## 判断贪心正确性 对于每一个给定的字符,它的右边只有一个答案。而如果没有分节,最小值肯定是最优的,没有必要把所有给定字符的位置全部记录下来,因为它距离右边的第一个 $\texttt{g}$ 肯定是最远的,因此这个贪心算法是完全正确的。 ## 代码 ```cpp #include <iostream> #include <cstring> // 使用string类进行操纵,可以更好地连接字符串 using namespace std; int t, n, ind = 1e9, ans = -1; // 细节*1:ind需要记录最小值,ans可能存在0的情况,保险 char c; string s; int main() { for (cin >> t; t; --t) { cin >> n >> c >> s; s += s /*调用string重载运算符拷贝字符串*/ , ans = -1, ind = 1e9; // 细节*2:多组数据记得清空! for (int i = 0; i < s.size(); ++i) { //遍历每个字符 if (s[i] == c) { // 如果是开头 ind = min(ind, i); // 记录最优值 } if (s[i] == 'g') { // 细节*3:有可能给定字符就是g,不可写成else if ans = max(ans, i - ind); // 记录答案 ind = 1e9; // 细节*4:此时已经分节了,ind需要重新计算 } } cout << ans << '\n'; } return 0; } ```