1717: [Usaco2006 Dec]Milk Patterns 产奶的模式
2024-08-29 07:53:23
1717: [Usaco2006 Dec]Milk Patterns 产奶的模式
Time Limit: 5 Sec Memory Limit: 64 MB
Submit: 1469 Solved: 799
[Submit][Status][Discuss]
Description
农夫John发现他的奶牛产奶的质量一直在变动。经过细致的调查,他发现:虽然他不能预见明天产奶的质量,但连续的若干天的质量有很多重叠。我们称之为一个“模式”。 John的牛奶按质量可以被赋予一个0到1000000之间的数。并且John记录了N(1<=N<=20000)天的牛奶质量值。他想知道最长的出现了至少K(2<=K<=N)次的模式的长度。比如1 2 3 2 3 2 3 1 中 2 3 2 3出现了两次。当K=2时,这个长度为4。
Input
* Line 1: 两个整数 N,K。
* Lines 2..N+1: 每行一个整数表示当天的质量值。
Output
* Line 1: 一个整数:N天中最长的出现了至少K次的模式的长度
Sample Input
8 2
1
2
3
2
3
2
3
1
1
2
3
2
3
2
3
1
Sample Output
4
题意
给定一个字符串,求至少出现k次的可重叠最长重复子串。
分析
后缀数组求出height(排名相邻的两个后缀的公共前缀),二分长度,在height中O(n)判断。
要求有连续k-1个height的值大于等于当前二分的长度才可以。
时间复杂度O(nlogn)
直接二分+hash也可以,复杂度相同
code
#include<cstdio>
#include<cstring>
#include<algorithm> using namespace std; const int N = ; int s[N];
int t1[N],t2[N],c[N],sa[N],height[N],rank[N];
int n,m = ,k; void get_sa() {
int i,p,*x = t1,*y = t2;
for (i=; i<m; ++i) c[i] = ;
for (i=; i<n; ++i) x[i] = s[i],c[x[i]]++;
for (i=; i<m; ++i) c[i] += c[i-];
for (i=n-; i>=; --i) sa[--c[x[i]]] = i;
for (int k=; k<=n; k<<=) {
p = ;
for (i=n-k; i<n; ++i) y[p++] = i;
for (i=; i<n; ++i) if(sa[i]>=k) y[p++]=sa[i]-k;
for (i=; i<m; ++i) c[i] = ;
for (i=; i<n; ++i) c[ x[y[i]] ]++;
for (i=; i<m; ++i) c[i] += c[i-];
for (i=n-; i>=; --i) sa[--c[ x[y[i]] ]] = y[i];
swap(x,y);
p = ;
x[sa[]] = ;
for (i=; i<n; ++i)
x[sa[i]] = (y[sa[i-]]==y[sa[i]] && sa[i-]+k<n && sa[i]+k<n &&
y[sa[i-]+k]==y[sa[i]+k]) ? p- : p++;
if (p>=n) break;
m = p;
}
}
void get_height() {
for (int i=; i<n; ++i) rank[sa[i]] = i;
int k = ;
height[] = ;
for (int i=; i<n; ++i) {
if (!rank[i]) continue;
if (k) k--;
int j = sa[rank[i]-];
while (i+k<n && j+k<n && s[i+k]==s[j+k]) k++;
height[rank[i]] = k;
}
}
bool check(int x) {
int num = ;
for (int i=; i<n; ++i) {
if (height[i] >= x) {
num ++;
if (num == k-) return true;
}
else num = ;
}
return false;
}
int main () {
scanf("%d%d",&n,&k);
for (int i=; i<n; ++i) scanf("%d",&s[i]);
get_sa();
get_height();
int L = ,R = n,mid,ans;
while (L <= R) {
mid = (L + R) >> ;
if (check(mid)) ans = mid,L = mid + ;
else R = mid - ;
}
printf("%d",ans);
return ;
}
最新文章
- UML类图关系全面剖析
- TCP、UDP、IP 协议分析
- Java:泛型
- Android Studio使用教程
- php面试题之四——Linux部分(高级部分)
- 【BZOJ】3669: [Noi2014]魔法森林(lct+特殊的技巧)
- 【M8】了解各种不同意义的new和delete
- 【转】ldconfig和ldd用法
- 使用EasyBCD 从硬盘安装 deepin2014.1
- 【Splay】例题
- 在写一点关于MySQL的知识,感觉自己mmd
- nginx+apache前后台搭配使用
- TypeError: Error #1034: 强制转换类型失败:无法将 ";"; 转换为 Array。
- 手持机设备公司(WINCE/ANDROID/LINUX)
- C++/C代码审查注意事项(摘录,非原创)
- 动态改变Spring定时任务执行频率
- xlrd 安装步骤
- JSP页面实现自动跳转
- 你所需要的sql数据库资料
- Hibernate多对一关联关系