作为礼物的字符串
首先这道题最暴力的想法就是给每个相同的字符在并查集上合并,最后暴力判断,但是这样复杂度是 会得到一个 TLE
。
由于并查集具有可以合并的性质,因此可以使用神奇的 倍增 。
对于一个长度为 的回文串 来说,如果我们复制一份原字符串到末尾,那么对于一个回文子串 ,那么 ,那么我们可以用一个并查集 fa[u][k]
表示 以 为起点,长度为 的子串的根。
即如果 那么
然后对于最后的 我们可以将长度为 的子串拆分成两个长度为 的子串,然后重新进行 merge
,如果最后判断长度为 的所有字符是否符合回文串的条件即可。
代码
点击查看代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
constexpr int N = 2E5 + 10;
int fa[N][20];
int find(int x, int k) {
if (fa[x][k] != x) fa[x][k] = find(fa[x][k], k);
return fa[x][k];
}
void merge(int x, int y, int k) {
x = find(x, k), y = find(y, k);
if (x != y) fa[x][k] = y;
}
void solve() {
int n, m; cin >> n >> m;
int bit = __lg(n * 2);
for (int i = 1; i <= n * 2; i ++ ) {
for (int j = 0; j <= bit; j ++ ) {
if (j == 0)
fa[i][j] = i <= n ? i : 2 * n - i + 1;
else
fa[i][j] = i;
}
}
while (m -- ) {
int l1, r1; cin >> l1 >> r1;
int l2 = 2 * n - r1 + 1, r2 = 2 * n - l1 + 1;
for (int k = bit; k >= 0; k -- ) {
if (l1 + (1 << k) - 1 <= r1) {
merge(l1, l2, k);
l1 += 1 << k;
l2 += 1 << k;
}
}
}
for (int k = bit; k >= 1; k -- ) {
for (int i = 1; i + (1 << k) - 1 <= 2 * n; i ++ ) {
int pos = find(i, k);
merge(i, pos, k - 1);
merge(i + (1 << k - 1), pos + (1 << k - 1), k - 1);
}
}
int cnt = 0;
for (int i = 1; i <= n; i ++ ) if (find(i, 0) == find(n - i + 1, 0)) {
++ cnt;
}
if (cnt == n)
cout << "YES\n";
else
cout << "NO\n";
cout << cnt << "\n";
}
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!