当前位置: 首页 > news >正文

ARC113E Rvom and Rsrev

ARC113E Rvom and Rsrev

显然,最优是 b 尽量靠前且尽量多,而在满足 b 尽量多的时候,让 a 也尽量多。

考虑分类讨论。

a a a 结尾

显然,不管怎样都不会删除 b,考虑怎样让 a 尽量多。

显然,最后的 b 全在开头且连在一起,所以删 a 的本质就是使 b 连起来。

那么我们一次删除 a 至少连接一次 b,至多连接两次 b

  • 选取一个 bAbb(a+)b 中的 a 进行删除能连接一次 b。(其中 A 表示两个及以上个 a 连起来,a+ 表示任意个 a 连起来)
  • 选取两个 bab 中的 a 进行删除能连接两次 b

所以先操作情况二,最后处理剩余 a ,这样能做到总的操作次数最少(不包括最后的 a 串)。

具体地,记录长度为 1 1 1a 串和长度大于 1 1 1 a a a 串的个数,分别记为 a 1 a1 a1 a 2 a2 a2,不包括最后的 a 串。

最少 a 删除操作次数即为 ⌊ a 1 2 ⌋ + ( a 1   m o d   2 ) + a 2 \lfloor\frac{a1}{2}\rfloor+(a_1 \bmod 2)+a2 2a1+(a1mod2)+a2

b b b 结尾

a a a 有偶数个

显然,最后全删 a 的字典序最大。

a a a 有奇数个

a b ab ab 结尾

奇数个 a​,显然 a 删不完,那么这个 ab 结尾的 b 肯定无法移动到前面。

显然,把 ab 前面的 a 全删完更优,前缀 b 的个数减一个连续。

a b b abb abb 结尾

同上,把 abb 前面的 a 全删完更优,前缀 b 的个数减二个连续。

b b b bbb bbb 结尾
(a+)(b+)

结果只有 a ( b + ) a(b+) a(b+)

(a+)(…)(b+)

其中一定有 ba,一定要操作且仅操作一次 b

答案一定是 (b+)(a+) 其中 b 的个数少两个。

首先,操作 b 的时候一定选的是 bab,因为其余情况,都无法让结尾变成 a,而结尾不是 a 的情况得不到更长的 b 的前缀。

把它的 b 和末尾的 b 交换,一定能 b 少两个且以 a 结尾,将后面两个 b 提前。

交换完后又是以 a 结尾的情况,计算最后交换后长度为 1 1 1a 串和长度大于 1 1 1 a a a 串的变化量即可。


结束讨论,时间复杂度 O ( ∑ ∣ S ∣ ) \mathcal O(\sum|S|) O(S)

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
#define he putchar('\n')
#define ha putchar(' ')

inline int read() {
	int x = 0, f = 1;
	char c = getchar();
	while (c < '0' || c > '9') {
		if (c == '-') f = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9') {
		x = x * 10 + c - '0';
		c = getchar();
	}
	return x * f;
}

inline void write(int x) {
	if (x < 0) {
		putchar('-');
		x = -x;
	}
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}

const int _ = 2e5 + 10;

int T, n, cnt[2];

char s[_];

signed main() {
	T = read();
	while (T--) {
		scanf("%s", s);
		n = strlen(s);
		cnt[0] = cnt[1] = 0;
		for (int i = 0; i < n; ++i) cnt[s[i] - 'a']++;
		if (cnt[0] == 0 || cnt[1] == 0) {
			printf("%s\n", s);
			continue;
		}
		int a1 = 0, a2 = 0, nw = 0;
		for (int i = n - 1; i >= 0; --i)
			if (s[i] == 'b') {
				for (int j = i - 1; j >= 0; --j)
					if (s[j] == 'a') nw++;
					else if (nw) {
						if (nw == 1) a1++;
						else a2++;
						nw = 0;
					}
				if (nw) {
					if (nw == 1) a1++;
					else a2++;
					nw = 0;
				}
				break;
			}
		//		cout << a1 << " " << a2 << "!!!!\n";
		if (s[n - 1] == 'a') {
			for (int i = 1; i <= cnt[1]; ++i) printf("b");
			for (int i = 1; i <= cnt[0] - 2 * (a1 / 2 + a1 % 2 + a2); ++i) printf("a");
			printf("\n");
		} else if (cnt[0] % 2 == 0) {
			for (int i = 1; i <= cnt[1]; ++i) printf("b");
			printf("\n");
		} else if (s[n - 2] == 'a') {
			// ab
			for (int i = 1; i <= cnt[1] - 1; ++i) printf("b");
			printf("ab\n");
		} else if (s[n - 3] == 'a') {
			// abb
			for (int i = 1; i <= cnt[1] - 2; ++i) printf("b");
			printf("abb\n");
		} else {
			// bbb
			int la = 0, lb = n;
			for (int i = 0; i < n; ++i)
				if (s[i] == 'a') la = max(la, i);
				else lb = min(lb, i);
			if (la < lb) {
				// aaabbb
				printf("a");
				for (int i = 1; i <= cnt[1]; ++i) printf("b");
				printf("\n");
			} else {
				// aaa...bbb
				bool flg = 0;
				for (int i = 0; i <= n - 3; ++i)
					if (s[i] == 'b' && s[i + 1] == 'a' && s[i + 2] == 'a') flg = 1;
				if (flg) {
					// aaa...baa...bbb
					for (int i = 1; i <= cnt[1] - 2; ++i) printf("b");
					for (int i = 1; i <= cnt[0] - 2 * (a1 / 2 + a1 % 2 + a2 - 1); ++i) printf("a");
					printf("\n");
				} else {
					// aaa...ba...bbb
					for (int i = 1; i <= cnt[1] - 2; ++i) printf("b");
					for (int i = 1; i <= cnt[0] - 2 * ((a1 - 1) / 2 + (a1 - 1) % 2 + a2); ++i) printf("a");
					printf("\n");
				}
			}
		}
	}
	return 0;
}

相关文章:

  • Windows与网络基础-26-IP地址概述
  • 模拟用户登录功能的实现以及演示SQL注入现象
  • 天龙八部科举答题问题和答案(全3/8)
  • CH342芯片应用—硬件设计指南
  • 【Android】-- 如何使用按钮和图片(点击事件、长按点击、同时展示文本和图像、ImageView)
  • 什么是文件格式的幻数
  • 【数据结构】绪论
  • C++的4种管理数据内存的方式
  • 中秋节的月亮怎么拍?不用手机和相机,程序员照样能拍出大片的感觉
  • Windows性能监控工具ypeperf
  • Python基础语法(二)—— 条件语句(if)+循环语句(for+while)
  • webpack基础使用
  • 基于蜜蜂算法求解电力系统经济调度(Matlab代码实现)
  • 我的vue的学习之旅
  • 【新学期、新Flag】快来参与活动、获取丰厚的奖励吧
  • 78. Subsets
  • Android交互
  • Brief introduction of how to 'Call, Apply and Bind'
  • express + mock 让前后台并行开发
  • iOS仿今日头条、壁纸应用、筛选分类、三方微博、颜色填充等源码
  • Spring Cloud Feign的两种使用姿势
  • Spring Cloud中负载均衡器概览
  • vue的全局变量和全局拦截请求器
  • 阿里云前端周刊 - 第 26 期
  • 关于springcloud Gateway中的限流
  • 开源地图数据可视化库——mapnik
  • 日剧·日综资源集合(建议收藏)
  • 三分钟教你同步 Visual Studio Code 设置
  • 时间复杂度与空间复杂度分析
  • 想使用 MongoDB ,你应该了解这8个方面!
  • 再次简单明了总结flex布局,一看就懂...
  • 走向全栈之MongoDB的使用
  • 阿里云API、SDK和CLI应用实践方案
  • ​比特币大跌的 2 个原因
  • ​用户画像从0到100的构建思路
  • # 手柄编程_北通阿修罗3动手评:一款兼具功能、操控性的电竞手柄
  • #{}和${}的区别?
  • #QT(TCP网络编程-服务端)
  • #单片机(TB6600驱动42步进电机)
  • (1综述)从零开始的嵌入式图像图像处理(PI+QT+OpenCV)实战演练
  • (办公)springboot配置aop处理请求.
  • (二)七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (附源码)ssm捐赠救助系统 毕业设计 060945
  • (剑指Offer)面试题41:和为s的连续正数序列
  • (原創) X61用戶,小心你的上蓋!! (NB) (ThinkPad) (X61)
  • (中等) HDU 4370 0 or 1,建模+Dijkstra。
  • (转)ABI是什么
  • (转)AS3正则:元子符,元序列,标志,数量表达符
  • (转)EOS中账户、钱包和密钥的关系
  • (转)fock函数详解
  • ****** 二 ******、软设笔记【数据结构】-KMP算法、树、二叉树
  • . Flume面试题
  • .NET Core 控制台程序读 appsettings.json 、注依赖、配日志、设 IOptions
  • .Net6 Api Swagger配置
  • .net访问oracle数据库性能问题