#P2181. 2024.10.13-第2题-字典序
-
1000ms
Tried: 211
Accepted: 25
Difficulty: 4
所属公司 :
字节
时间 :2024年10月13日
-
算法标签>贪心算法
2024.10.13-第2题-字典序
对于给定的字符串,算出字符串中0的个数,1的个数,记d为min({0的个数,1的个数,k})那么最多将从前往后数d个1与从后往前数d个0交换,注意当n为2时,因为要恰好交换k次所以当k为奇数时,01这种字符串得交换一次成10
c++
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+10;
void solve() {
int n, k;
cin >> n >> k;
string s;
cin >> s;
// 特殊情况:如果 n 等于 2
if (n == 2) {
if (k & 1) swap(s[0], s[1]); // 如果 k 是奇数,交换两个字符
cout << s << endl;
return;
}
int c1 = 0, c0 = 0; // 计数变量,c1 记录 '1' 的数量,c0 记录 '0' 的数量
for (int i = 0; i < n; i++) c1 += (s[i] == '1'); // 统计 '1' 的数量
c0 = n - c1; // 计算 '0' 的数量
k = min({k, c0, c1});
int m = k;
// 将前 m 个 '1' 变为 '0'
for (int i = 0; i < n; i++) {
if (s[i] == '1') {
if (m) {
m--; // 减少可交换次数
s[i] = '0'; // 进行交换
}
}
}
m = k;
// 将后 m 个 '0' 变为 '1'
for (int i = n - 1; i >= 0; i--) {
if (s[i] == '0') {
if (m) {
m--;
s[i] = '1';
}
}
}
cout << s << endl;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int t;
cin >> t;
while (t--) {
solve();
}
}
python
def solve():
n, k = map(int, input().split()) # 读取字符串长度 n 和可交换的次数 k
s = input().strip() # 读取字符串 s
# 特殊情况:如果 n 等于 2
if n == 2:
if k % 2 == 1: # 如果 k 是奇数
s = s[1] + s[0] # 交换两个字符
print(s) # 输出结果
return
c1 = s.count('1') # 统计 '1' 的数量
c0 = n - c1 # 计算 '0' 的数量
k = min(k, c0, c1) # 取 k 的最小值,保证不超过 '0' 和 '1' 的数量
m = k # 备份 k 的值
# 将前面的 '1' 替换为 '0'
s_list = list(s) # 将字符串转换为列表以便修改
for i in range(n):
if s_list[i] == '1' and m > 0: # 如果是 '1' 且还有可交换次数
m -= 1 # 减少可交换次数
s_list[i] = '0' # 进行替换
m = k # 重新备份 k 的值
# 将后面的 '0' 替换为 '1'
for i in range(n - 1, -1, -1):
if s_list[i] == '0' and m > 0: # 如果是 '0' 且还有可交换次数
m -= 1 # 减少可交换次数
s_list[i] = '1' # 进行替换
print("".join(s_list)) # 输出结果
if __name__ == "__main__":
t = int(input()) # 读取测试案例数量
for _ in range(t):
solve() # 调用解决函数
java
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int t = scanner.nextInt(); // 读取测试案例数量
while (t-- > 0) {
solve(scanner); // 调用解决函数
}
scanner.close(); // 关闭扫描器
}
private static void solve(Scanner scanner) {
int n = scanner.nextInt(); // 读取字符串长度 n
int k = scanner.nextInt(); // 读取可交换的次数 k
String s = scanner.next(); // 读取字符串 s
// 特殊情况:如果 n 等于 2
if (n == 2) {
if (k % 2 == 1) { // 如果 k 是奇数
s = s.charAt(1) + "" + s.charAt(0); // 交换两个字符
}
System.out.println(s); // 输出结果
return;
}
int c1 = 0, c0 = 0; // 计数变量,c1 记录 '1' 的数量,c0 记录 '0' 的数量
for (int i = 0; i < n; i++) {
if (s.charAt(i) == '1') {
c1++; // 统计 '1' 的数量
}
}
c0 = n - c1; // 计算 '0' 的数量
k = Math.min(k, Math.min(c0, c1)); // 取 k 的最小值,确保不超过 '0' 和 '1' 的数量
int m = k; // 备份 k 的值
StringBuilder sb = new StringBuilder(s); // 创建可修改的字符串构建器
// 将前面的 '1' 替换为 '0'
for (int i = 0; i < n; i++) {
if (sb.charAt(i) == '1' && m > 0) { // 如果是 '1' 且还有可交换次数
m--; // 减少可交换次数
sb.setCharAt(i, '0'); // 进行替换
}
}
m = k; // 重新备份 k 的值
// 将后面的 '0' 替换为 '1'
for (int i = n - 1; i >= 0; i--) {
if (sb.charAt(i) == '0' && m > 0) { // 如果是 '0' 且还有可交换次数
m--; // 减少可交换次数
sb.setCharAt(i, '1'); // 进行替换
}
}
System.out.println(sb.toString()); // 输出结果
}
}
题目内容
小红有一个长为n的只由0和1组成的串s,他需要恰好对s执行k次交换操作。小红想要使得s的字典序最小,
请你帮帮他求出最小字典序的s吧。 选择两个不同的下标并交换这两个位置上的值称为一次交换,使用数学的方式描述,即选择和j(1≤i<j≤n)并交换si和sj。 当且仅当满足以下条件之一时,字符串a按字典顺序小于字符串b:
- a是b的前缀,但是a=b;
- 对于a与b的第一个不相同的位置,字符串a中的字母在字母表中的位置前于b中相应的字字母。
输入描述
每个测试文件均包含多组测试数据。
第一行输入一个整数T(1≤T≤104)代表数据组数,每组测试数据描述如下:
第一行输入两个整数n和k(2≤n≤2×105;1≤k≤109)代表s的长度和操作次数。
第二行输入一个长为n,且只由'0'和'1'组成的字符串s。 除此之外,保证所有的n之和不超过2×105。
输出描述
对于每一组测试数据,在一行上输出一个长度为n,且只由0和1组成的字符串,代表进行了恰好k次操作后,字典序最小的s。
样例1
输入
2
6 2
110000
2 10
11
输出
000011
11
说明
对于第一组测试数据,需要恰好进行k=2次操作,依次交换s1,s6和s2,s5。