POJ3261——Milk Patterns 后缀数组

POJ3261

题意大概就是求一串数字中……应该说,当字符串看的数字中,找到一个至少出现k次的最长的子序列(可重复)


嗯。。课件完全看不懂在说什么


将问题转化成,求 height 数组中最大的长度为 K 的子序列的最小值
然后随便则么搞都可以了。。。。。

???

首先我们考虑height数组的一个结论:Height[rank[i]]>=Height[rank[i-1]]-1

联想其证明过程,显然可以得到:若Height[i]!=0,则与Height[i-1]所得的值,必然是同一个前缀得到的


那么我们可以得知:如果x个连续的Height值都大于T,那么就有x+1个长度至少为T的字符串

所以我们二分一个x,O(n)判断即可

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#include <string>
#include <map>
#include <cstring>
#include <ctime>
#include <vector>
#define inf 1e9
#define ll long long
#define For(i,j,k) for(int i=j;i<=k;i++)
#define Dow(i,j,k) for(int i=k;i>=j;i--)
using namespace std;
inline void read(int &tx){   ll x=0,f=1;char ch=getchar();   while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}  while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}  tx=x*f; }
inline void write(ll x){    if (x<0) putchar('-'),x=-x; if (x>=10) write(x/10);   putchar(x%10+'0');  }
inline void writeln(ll x){write(x);puts("");}
int  s[50001];
int rk[50001],ys[50001],kk,n,het[50001];
struct node{int num,v,rk;}	t[50001];
inline bool cmp(node x,node y){return x.rk!=y.rk?x.rk<y.rk:x.v<y.v;}
inline bool check(int x)
{
	int tot=0,mx=0;
	For(i,1,n)
	{
		if(het[i]>=x)	tot++;else tot=0;
		if(tot+1>=kk)	return 1;
	}
	return 0;
}
int main()
{
	read(n);read(kk);
	For(i,1,n)	read(s[i]);
	For(i,1,n)	rk[i]=s[i];
	for(int i=0;(1<<i)<=n;i++)
	{
		For(j,1,n)
			t[j].num=j,t[j].v=rk[j+(1<<i)],t[j].rk=rk[j];
		sort(t+1,t+n+1,cmp);
		int num=0;
		For(j,1,n)
		{
			if(t[j].v!=t[j-1].v||t[j].rk!=t[j-1].rk)	num++;
			rk[t[j].num]=num;
		}
	}
	For(i,1,n)	ys[rk[i]]=i;
	int k=0;
	For(i,1,n)
	{
		for(k-=(k!=0);s[i+k]==s[ys[rk[i]-1]+k];k++);
		het[rk[i]]=k;	
	}
	int l=1,r=n,ans=0;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(check(mid))	ans=max(ans,mid),l=mid+1;else r=mid-1;
	}
	writeln(ans);
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值