为了更好的阅读体检,可以查看我的算法学习网
在线评测链接:P1477
视频题解
题目内容
塔子哥有一个字符串 s s s 。
现在塔子哥给这个串恰好 k k k 次修改,问修改后的串是否可能是回文串?需要保证修改一个字符后,修改前后的字符不同。
输入描述
第一行,一个整数 T ( 1 ≤ T ≤ 10 ) T(1\leq T\leq 10) T(1≤T≤10) ,表示 T T T 组数据。
接下来对于每组数据,
第一行,输入一个字符串 s ( 1 ≤ l e n ( s ) ≤ 1 0 6 ) s (1\leq len(s)\leq 10^6) s(1≤len(s)≤106) 。
第二行,输入一个整数 k ( 1 ≤ k ≤ 1 0 6 ) k(1\leq k\leq 10^6) k(1≤k≤106) ,表示修改次数。
输出描述
输出 Yes
表示修改后可以为回文串,输出 No
表示在
k
k
k 次修改后不可能为回文串。
样例
输入
4
aaa
1
bac
2
bbcc
3
cdefgh
2
输出
Yes
Yes
Yes
No
思路:思维
首先考虑将 s [ i ] s[i] s[i] 与 s [ j ] s[j] s[j] 修改为相同,满足 0 ≤ i , j ≤ n − 1 , i + j = n − 1 0\leq i, j\leq n-1, i+j=n-1 0≤i,j≤n−1,i+j=n−1。
如果修改了 c n t cnt cnt 次:
-
c n t > k cnt > k cnt>k ,则必然无法修改为回文串。
-
c n t = = k cnt == k cnt==k ,则恰好可以修改为回文串
-
c n t < k cnt < k cnt<k 但是 n n n 是奇数,那么多的 k − c n t k - cnt k−cnt 次都用来修改最中间的字符即可
-
c n t < k cnt < k cnt<k 但是 n n n 是偶数,那么多的 k − c n t k - cnt k−cnt 可以这么考虑:
如果 k − c n t k - cnt k−cnt 为偶数,那么我们对于相同的两个字符 s [ i ] = s [ j ] s[i]=s[j] s[i]=s[j],修改 k − c n t 2 \frac{k - cnt}{2} 2k−cnt 次这两个字符即可。
如果 k − c n t k - cnt k−cnt 为奇数,且 c n t > 0 cnt > 0 cnt>0,那么我们对于修改前不相同的两个字符 s [ i ] s[i] s[i] 和 s [ j ] s[j] s[j] ,假设 s [ i ] = ′ a ′ , s [ j ] = ′ b ′ s[i]='a', s[j]='b' s[i]=′a′,s[j]=′b′ ,那么我们不把 s [ i ] s[i] s[i] 修改为和 s [ j ] s[j] s[j] 一样,此时剩余了 k − c n t + 1 k-cnt+1 k−cnt+1 次,因为 k − c n t k-cnt k−cnt 是奇数,所以 k − c n t + 1 k-cnt+1 k−cnt+1 是偶数且大于等于 2 2 2 。这时候可以将 s [ i ] s[i] s[i] 和 s [ j ] s[j] s[j] 都修改为 ′ c ′ 'c' ′c′ 。后面剩余的 k − c n t − 1 k-cnt-1 k−cnt−1 次,均可以选择 s [ i ] s[i] s[i] 和 s [ j ] s[j] s[j] 同时修改为一个同样的字符即可。
如果 k − c n t k - cnt k−cnt 为奇数,且 c n t = 0 cnt = 0 cnt=0 ,如果 k − c n t > 1 k - cnt > 1 k−cnt>1 ,则必然可以修改为回文串,否则 k − c n t = 1 k - cnt = 1 k−cnt=1 ,就无法修改为回文串。
时间复杂度: O ( n ) O(n) O(n)
代码
C++
#include <bits/stdc++.h>
using namespace std;
string s;
int k;
void solve() {
cin >> s;
cin >> k;
int n = int(s.size());
// 先查看有多少需要修改的
int cnt = 0;
for (int l = 0, r = n - 1; l < r; ++l, --r) {
if (s[l] != s[r]) {
cnt += 1;
}
}
if (cnt > k) {
cout << "No\n";
return;
}
if (cnt == k || (n & 1)) {
cout << "Yes\n";
return;
}
// k > cnt, n 是偶数
// 如果 k - cnt 是偶数,则修改完后,将一个字符反复修改再修改回来即可
if ((k - cnt) % 2 == 0) {
cout << "Yes\n";
} else {
// 如果 k - cnt 是奇数,cnt > 0 或者 (cnt == 0 && k - cnt > 1),则可以
if (cnt > 0 || k - cnt > 1) {
cout << "Yes\n";
} else {
// cnt == 0 and k - cnt == 1 ,则不可以
cout << "No\n";
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) solve();
return 0;
}
Java
import java.util.Scanner;
public class Main {
private static Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
int T = scanner.nextInt();
while (T-- > 0) {
solve();
}
}
private static void solve() {
String s = scanner.next();
int k = scanner.nextInt();
int n = s.length();
int cnt = 0;
for (int l = 0, r = n - 1; l < r; ++l, --r) {
if (s.charAt(l) != s.charAt(r)) {
cnt += 1;
}
}
if (cnt > k) {
System.out.println("No");
return;
}
if (cnt == k || (n & 1) == 1) {
System.out.println("Yes");
return;
}
if ((k - cnt) % 2 == 0) {
System.out.println("Yes");
} else {
if (cnt > 0 || k - cnt > 1) {
System.out.println("Yes");
} else {
System.out.println("No");
}
}
}
}