题解:洛谷 P2852 [USACO06DEC] Milk Patterns G
【题目来源】
洛谷:[P2852 USACO06DEC] Milk Patterns G - 洛谷
【题目描述】
农夫约翰注意到他的奶牛所产的牛奶质量每天都在变化。经过进一步调查,他发现虽然无法预测牛奶质量从一天到下一天的变化,但每天的牛奶质量中存在一些规律模式。
为了进行严格的研究,他发明了一种复杂的分类方案,其中每个牛奶样本被记录为一个介于 \(0\) 和 \(1,000,000\) 之间的整数,并记录了一头奶牛在 \(N\ (1 \le N \le 20,000)\) 天内的数据。他希望找到一个最长的样本模式,该模式至少重复 \(K\ (2 \le K \le N)\) 次。这可能包括重叠的模式——例如,1 2 3 2 3 2 3 1 中的 2 3 2 3 重复了两次。
帮助农夫约翰找到样本序列中最长的重复子序列。保证至少有一个子序列重复至少 \(K\) 次。
【输入】
第 \(1\) 行:两个用空格分隔的整数:\(N\) 和 \(K\)。
第 \(2\) 行到第 \(N+1\) 行:\(N\) 个整数,每行一个,第 \(i\) 行表示第 \(i\) 天的牛奶质量。
【输出】
第 \(1\) 行:一个整数,表示至少出现 \(K\) 次的最长模式的长度。
【输入样例】
8 2
1
2
3
2
3
2
3
1
【输出样例】
4
【算法标签】
《洛谷 P2852 Milk Patterns》 #二分# #哈希hashing# #后缀数组SA# #USACO# #2006#
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 20005;
int n, k;
string s, a[N];
int sa[N]; // 前缀和数组,sa[i]表示前i个字符串拼接后的总字符数
// 检查是否存在长度为x的连续字符串组合出现至少k次
bool check(int x)
{
// cout << "x " << x << endl;
map<string, int> mp;
for (int i = 1; i + x - 1 <= n; i++)
{
// 计算子串的起始和结束位置
int st_pos = sa[i] - a[i].size() + 1; // 第i个字符串的起始位置
int ed_pos = sa[i + x - 1]; // 第(i+x-1)个字符串的结束位置
// 提取子串
string tmp = s.substr(st_pos, ed_pos - st_pos + 1);
mp[tmp]++; // 统计该子串出现的次数
}
int maxn = -1e9;
for (auto t : mp)
{
maxn = max(maxn, t.second); // 找到出现次数最多的子串
}
return maxn >= k; // 判断是否有子串出现至少k次
}
int main()
{
cin >> n >> k;
s = " "; // 在字符串前加一个空格,使索引从1开始
for (int i = 1; i <= n; i++)
{
cin >> a[i];
s += a[i]; // 将所有字符串拼接成一个长字符串
}
// 计算前缀和:sa[i]表示前i个字符串的总字符数
for (int i = 1; i <= n; i++)
{
sa[i] = sa[i - 1] + a[i].size();
}
int l = 0, r = n;
// 二分查找最大满足条件的x
while (l < r)
{
int mid = (l + r + 1) / 2;
if (check(mid))
{
l = mid; // 满足条件,尝试更大的x
}
else
{
r = mid - 1; // 不满足条件,减小x
}
}
cout << l << endl;
return 0;
}
【运行结果】
8 2
1
2
3
2
3
2
3
1
4
浙公网安备 33010602011771号