题解:洛谷 P14975 COW Splits
【题目来源】
洛谷:P14975 [USACO26JAN1] COW Splits B - 洛谷
【题目描述】
给定 Bessie 一个正整数 \(N\) 和一个长度为 \(3N\) 的字符串 \(S\),该字符串是由 \(N\) 个长度为 \(3\) 的字符串拼接而成,每个字符串都是 \(\texttt{COW}\) 的一个循环移位。换句话说,每个字符串将是 \(\texttt{COW}\)、\(\texttt{OWC}\) 或 \(\texttt{WCO}\) 中的一个。
字符串 \(X\) 是一个平方串,当且仅当存在一个字符串 \(Y\) 使得 \(X = Y + Y\),其中 \(+\) 表示字符串拼接。例如,\(\texttt{COWCOW}\) 和 \(\texttt{CC}\) 是平方串的例子,但 \(\texttt{COWO}\) 和 \(\texttt{OC}\) 不是。
在一次操作中,Bessie 可以从 \(S\) 中移除任意一个子序列 \(T\),其中 \(T\) 是一个平方串。一个字符串的子序列是指通过从原字符串中删除若干(可以是零个)字符而得到的字符串。
你的任务是帮助 Bessie 判断是否可能将 \(S\) 转化为空字符串。此外,如果可能,你必须提供一种实现方法。
Bessie 还会收到一个参数 \(k\),其值为 \(0\) 或 \(1\)。设 \(M\) 为你构造方案中的操作次数。
- 如果 \(k = 0\),则 \(M\) 必须等于可能的最小操作次数。
- 如果 \(k = 1\),则 \(M\) 最多可以比可能的最小操作次数多 \(1\)。
【输入】
第一行包含 \(T\),表示独立测试用例的数量(\(1\le T\le 10^4\)),以及 \(k\)(\(0 \le k \le 1\))。
每个测试用例的第一行有 \(N\)(\(1 \le N \le 10^5\))。
每个测试用例的第二行有 \(S\)。
所有测试用例的 \(N\) 之和不超过 \(10^5\)。
【输出】
对于每个测试用例,按照以下流程输出一行或两行。如果不可能将 \(S\) 转化为空字符串,则在一行中输出 \(-1\)。
否则,在第一行输出 \(M\)——你构造方案中的操作次数。在第二行,输出 \(3N\) 个由空格分隔的整数。第 \(i\) 个整数 \(x\) 表示 \(S\) 的第 \(i\) 个字母是在第 \(x\) 次操作中被删除的(\(1 \le x \le M\))。
【输入样例】
3 1
3
COWOWCWCO
4
WCOCOWWCOCOW
6
COWCOWOWCOWCOWCOWC
【输出样例】
-1
1
1 1 1 1 1 1 1 1 1 1 1 1
3
3 3 2 3 3 2 1 1 1 1 1 1 1 1 1 1 1 1
【核心思想】
- 问题分析:给定一个长度为 \(3N\) 的字符串 \(S\),它由 \(N\) 个块组成,每个块都是
"COW"的循环移位(即"COW"、"OWC"或"WCO")。每次操作可以删除 \(S\) 中的一个平方串子序列(即形如 \(Y+Y\) 的字符串,不要求连续)。目标是判断能否通过若干次操作将 \(S\) 删空,并构造一种操作方案。同时,若 \(k=0\) 要求操作次数最小;若 \(k=1\) 允许比最小次数多 \(1\)。
关键洞察:由于每个块都是 "COW" 的循环移位,整个字符串 \(S\) 中每种字母恰好出现 \(N\) 次。要删除一个平方串 \(Y+Y\),本质上是选择两个相同的子序列 \(Y\) 和 \(Y'\) 配对删除。核心结论是:若 \(N\) 为奇数,则无法完成;若 \(N\) 为偶数,则一定能完成,且最小操作次数为 1(当整个字符串本身就是平方串)或 2(否则)。因为可以通过将 \(S\) 分成前后两半,对每对块进行字符匹配,构造出两次平方串删除操作。
-
算法选择:
- 构造 + 贪心匹配:首先判断整个字符串 \(S\) 是否为平方串(即前半部分等于后半部分)。若是,则一次操作即可删空。
- 否则,构造一个 2 次操作的方案:将 \(S\) 分成前后两半,每半长度均为 \(3N/2\)(需 \(N\) 为偶数)。对每对对应块(每块 3 个字符),将匹配的字符分配到操作 1,不匹配的分配到操作 2,使得操作 1 和操作 2 各自删除的字符序列都是平方串。
-
关键步骤(基于代码逻辑):
- 读入:\(T, k\),对每个测试用例读入 \(N\) 和字符串 \(S\)(长度为 \(3N\))。
- 检查 \(N\) 奇偶:若 \(N\) 为奇数,输出 -1(因为无法将字符串分成两个长度相等的部分来构造两次操作)。
- 检查一次操作可行性:判断 \(S\) 的前半段是否等于后半段。若是,输出
1和所有字符的操作编号为 1。 - 构造两次操作:
- 对于 \(i\) 从 0 到 \(N/2 - 1\),取前半段的第 \(i\) 个块和后半段的第 \(i\) 个块。
- 比较两个块中的三个字符,按照三种情况(
s[l] == s[r]、s[l] == s[r+1]、s[l] == s[r+2])将匹配的字符分配到操作 1,不匹配的分配到操作 2。 - 输出
2和所有字符的操作编号。
-
时间/空间复杂度:
- 时间复杂度:\(O(N)\),每个测试用例线性扫描。
- 空间复杂度:\(O(N)\),存储结果数组。
-
构造 + 匹配的核心思想:
- 平方串删除的本质:一次操作删除一个平方串 \(Y+Y\),意味着需要将 \(S\) 中的字符分成两组,每组内的字符序列相同。若要一次删完,则 \(S\) 本身必须是平方串。
- 两次操作的构造:将 \(S\) 分成两半,每半视为一个“模板”,通过调整字符分配到两个操作,使得每个操作中前半和后半的字符序列相同。由于每个块都是
"COW"的循环移位,块内三个字符互不相同,通过比较两个块的对应位置,总能找到一种配对方式,将三个字符分配给两个操作,使得每个操作得到的两个子序列相同。 - 奇偶限制:\(N\) 必须为偶数,因为需要将块平均分成两组(前半和后半),否则无法构造。
- 适用场景:适用于具有固定块结构(如循环移位)的字符串,要求通过删除平方串子序列来清空字符串的构造问题。核心是利用块的置换特性进行贪心匹配。
【解题思路】

【算法标签】
普及+ #构造
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 100005 * 3; // 数组最大容量
int t, k, n, num1, num2, num3; // t: 测试用例数,k: 参数(未使用),n: 字符串长度,其他为临时变量
string s; // 输入字符串
int a[N]; // 结果数组,存储每个字符的分配方案
// 检查字符串是否可被平分为两个相同的子串
bool check(string t)
{
for (int i = 0; i < s.size() / 2; i++)
{
if (s[i] != s[i + s.size() / 2])
{
return false;
}
}
return true;
}
int main()
{
cin >> t >> k; // 读入测试用例数和参数k(k未使用)
while (t--) // 处理每个测试用例
{
cin >> n; // 读入字符串长度
cin >> s; // 读入字符串
// 如果字符串长度为奇数,无法平分
if (n % 2 == 1)
{
cout << -1 << endl;
continue;
}
// 如果字符串已经可以平分为两个相同的子串
if (check(s))
{
cout << 1 << endl; // 只需要1种分配方案
for (int i = 0; i < s.size(); i++)
{
cout << 1 << " "; // 所有字符分配到第1组
}
cout << endl;
continue;
}
// 否则需要2种分配方案
// 将字符串分成前后两半,每3个字符为一组进行匹配
for (int i = 0; i < n / 2; i++)
{
int l = i * 3; // 前半段当前组的起始位置
int r = (i + n / 2) * 3; // 后半段对应组的起始位置
// 情况1:l位置的字符与r位置的字符相同
if (s[l] == s[r])
{
a[l] = a[l + 1] = a[r] = a[r + 1] = 1; // 这些位置分配到第1组
a[l + 2] = a[r + 2] = 2; // 剩余位置分配到第2组
}
// 情况2:l位置的字符与r+1位置的字符相同
else if (s[l] == s[r + 1])
{
a[l] = a[l + 1] = a[r + 1] = a[r + 2] = 1;
a[l + 2] = a[r] = 2;
}
// 情况3:l位置的字符与r+2位置的字符相同
else if (s[l] == s[r + 2])
{
a[l + 1] = a[l + 2] = a[r] = a[r + 1] = 1;
a[l] = a[r + 2] = 2;
}
}
cout << 2 << endl; // 需要2种分配方案
for (int i = 0; i < s.size(); i++)
{
cout << a[i] << " "; // 输出每个字符的分配方案
}
cout << endl;
}
return 0;
}
【运行结果】
3 1
3
COWOWCWCO
-1
4
WCOCOWWCOCOW
1
1 1 1 1 1 1 1 1 1 1 1 1
6
COWCOWOWCOWCOWCOWC
2
2 1 1 2 1 1 1 1 2 1 1 2 1 1 2 1 1 2
浙公网安备 33010602011771号