1 条题解
-
0
题解说明
问题背景:
给定一个字符串,要求将其中的所有'a'
字符重新排列,使得它们在字符串中关于中心对称。允许的操作是移动'a'
的位置,代价为移动距离。目标是计算最小的总移动距离。如果无法形成对称排列,则输出-1
。核心思路:
收集
'a'
的位置:- 遍历字符串,记录所有
'a'
的下标到数组 ,其中 是'a'
的总数。
不可行情况:
- 如果
'a'
的数量 和非'a'
的数量 都是奇数,则无法对称。 - 原因:字符串总长 为奇数时,中心位置是 。
- 若 和 都是奇数,则
'a'
和非'a'
都需要占据中心,矛盾。
- 若 和 都是奇数,则
- 此时直接输出
-1
。
计算最小移动距离:
- 对称位置的下标和为 (例如 与 , 与 )。
- 将第 个
'a'
与第 个'a'
配对,它们的目标位置和应为 。 - 移动代价为 。
- 遍历 ,累加代价。
中心
'a'
的处理:- 如果 为奇数,则有一个
'a'
需要放在中心位置 。 - 代价为 。
输出结果:
- 输出总代价 。
复杂度分析:
- 遍历字符串 。
- 计算代价 。
- 总体复杂度,空间复杂度 。
#include <bits/stdc++.h> using namespace std; const int maxn = 2e5 + 5; // 最大字符串长度(2*10^5 +5,适配题目数据规模) int n; // 字符串实际长度 char s[maxn]; // 存储输入的字符串(从索引1开始使用) int b[maxn], m; // b数组:存储字符串中所有'a'的位置;m:'a'的总个数 int main() { // 读取字符串(从索引1开始存储),并计算字符串长度n scanf("%s", s + 1), n = strlen(s + 1); // 遍历字符串,收集所有'a'的位置到b数组 for (int i = 1; i <= n; i++) { if (s[i] == 'a') { b[++m] = i; // 第m个'a'的位置是i(m从1开始计数) } } // 特殊情况判断:当'a'的数量为奇数,且非'a'的数量也为奇数时,无法对称排列 // 解释:总长度n = m('a'的数量) + (n-m)(非'a'的数量) // 若两者均为奇数,则n为偶数+奇数=奇数,此时对称中心为小数位置,而字符位置是整数,无法完美对称 if ((m & 1) & (n - m & 1)) { return 0 * puts("-1"); // 输出-1并结束程序 } long long ans = 0; // 存储最小移动距离总和(用long long避免溢出) // 计算对称位置的'a'的移动距离:第i个'a'与第m+1-i个'a'对称 // 对称中心的位置和为n+1(例如位置1与n对称,2与n-1对称,和均为n+1) for (int i = 1; (i << 1) <= m; i++) { // i << 1 <= m 等价于 i <= m/2 // 两个对称'a'的目标位置和应为n+1,当前位置和为b[i]+b[m+1-i] // 距离差的绝对值即为需要移动的总距离 ans += abs(n + 1 - b[i] - b[m + 1 - i]); } // 若'a'的数量为奇数,中间的'a'需要移动到整个字符串的中心位置 if (m & 1) { // m为奇数(m & 1 结果为1) // 字符串中心位置为(n+1)/2(整数除法) ans += abs((n + 1 >> 1) - b[(m + 1 >> 1)]); // m+1>>1 等价于 (m+1)/2,即中间'a'的索引 } // 输出计算得到的最小移动距离总和 return 0 * printf("%lld\n", ans); }
- 遍历字符串,记录所有
- 1
信息
- ID
- 3173
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者