CF2069D. Palindrome Shuffle

D. Palindrome Shuffle

题意

给定长度为 \(n\) ( \(n\) 为偶数) 字符串 \(s\), 你可以选择 \(s\) 的一个子串 \(t\) 并且随意交换 \(t\) 中每个字符顺序使得 \(s\) 成为回文串. 求 \(t\) 的最小长度.

算法

双指针, 字符串.

思路

首先可以发现对于相同的前后缀, 我们可以直接去掉, 不会影响答案.

再来思考对于中间的子串, 如何选择子串才能够最小化长度?

先来考虑一种特殊情况: abb | abb, 这种左右两部分字符集相等的情况只需要选择一侧进行交换即可成为回文串.

那么对于剩下的情况, 我们选择的子串会覆盖左右两侧的一部分, 现在问题是怎么选择子串长度最小. 现在考虑从左往右选. 对于每一个字符, 只要其在左侧的出现次数大于右边的出现次数就是合法的, 否则就需要更新区间. 注意这时左右两侧字符集是不相同的, 可能有的字符只在右侧出现过, 所以最后还需要在右侧更新一下右端点.

从右往左的操作是一样的, 将字符串翻转后再操作一次即可.

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
int deal() { int l = INF, r = -INF; for (int i = 1, t = 0, f = 0; i <= n >> 1; ++i) { if (!cnt[s[i] - 'a']) ++t; ++cnt[s[i] - 'a']; if (!cnt[s[i] - 'a']) --t; if (!cnt[s[n - i + 1] - 'a']) ++t; --cnt[s[n - i + 1] - 'a']; if (!cnt[s[n - i + 1] - 'a']) --t; if (t) l = min(l, i), f = 1; else if (f) r = max(r, i), f = 0; } for (int i = n / 2 + 1; i <= n; ++i) if (cnt[s[i] - 'a'] < 0) { cnt[s[i] - 'a'] += 2; r = i; } for (int i = 0; i < 26; ++i) cnt[i] = 0; if (l == INF) return 0; return r - l + 1; }
posted @   Steven1013  阅读(103)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
展开