dyllalala

导航

[poj 3261]Milk Patterns

后缀数组搞一下就可以了喵~

其实这道题的第一个想法是 SAM ,建完后缀自动机后拓扑排序跑一遍统计下每个子串的出现次数就 O(N) 就妥妥过掉了

后缀树也是 O(N) 的,统计一下每个节点对应的子树中有多少个叶子节点即可

可是看了一下数据范围,欸呦你妹啊,字符数 1000000+1 是什么心态啊!居然把我的后缀树和后缀 zdj 都卡掉了啊!

 

然后很痛苦的想了想后缀数组的做法:

搞出 sa, rank, height 三个数组后,跑一遍二分,用一个 tot 表示找到了几个子串

二分答案 L,O(N) 扫个遍如果 height[i]>=L 说明又找到一个子串,tot++,否则重新计算

不过注意这里 tot 的初始值是 1 而不是 0 

不过这么个写法怎么写都是 O(NlogN) 的了,如果有更好的写法,请教我做人喵~

 

#include <cstdio>
#include <cstring>
const int sizeOfN=20002;
const int sizeOfType=1200021;

namespace IOspace
{
	inline int getint()
	{
		register int num=0;
		register char ch;
		do ch=getchar(); while (ch<'0' || ch>'9');
		do num=num*10+ch-'0', ch=getchar(); while (ch>='0' && ch<='9');
		return num;
	}
	inline void putint(int num)
	{
		char stack[15];
		register int top=0;
		if (num==0) stack[top=1]='0';
		for ( ;num;num/=10) stack[++top]=num%10+'0';
		for ( ;top;top--) putchar(stack[top]);
		putchar('\n');
	}
}

int N, K;
int A[sizeOfN];

namespace suffixArray
{
	int sa[sizeOfN], rank[sizeOfN], height[sizeOfN];

	inline void swap(int *& x, int *& y) {int * t=x; x=y; y=t;}
	inline void buildArray()
	{
		static int t[2][sizeOfN];
		static int c[sizeOfType];
		int * x=t[0], * y=t[1];
		int M=sizeOfType;

		for (int i=0;i<M;i++) c[i]=0;
		for (int i=0;i<N;i++) c[x[i]=A[i]]++;
		for (int i=1;i<M;i++) c[i]+=c[i-1];
		for (int i=N-1;i>=0;i--) sa[--c[x[i]]]=i;

		for (int j=0, k=1;j<N;M=j, k<<=1)
		{
			j=0;
			for (int i=N-k;i<N;i++) y[j++]=i;
			for (int i=0;i<N;i++) if (sa[i]>=k) y[j++]=sa[i]-k;

			for (int i=0;i<M;i++) c[i]=0;
			for (int i=0;i<N;i++) c[x[y[i]]]++;
			for (int i=1;i<M;i++) c[i]+=c[i-1];
			for (int i=N-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];

			swap(x, y);
			j=1; x[sa[0]]=0;
			for (int i=1;i<N;i++)
				x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?j-1:j++;
		}
	}
	inline void calcHeight()
	{
		int l=0;
		for (int i=0;i<N;i++) rank[sa[i]]=i;
		for (int i=0;i<N;i++)
		{
			int j=sa[rank[i]-1];
			for (l=l?l-1:0;A[i+l]==A[j+l];l++);
			height[rank[i]]=l;
		}
	}
}

inline int search();

int main()
{
	N=IOspace::getint(), K=IOspace::getint();
	for (int i=0;i<N;i++) A[i]=IOspace::getint()+1;
	A[N++]=0;

	suffixArray::buildArray();
	suffixArray::calcHeight();

	IOspace::putint(search());

	return 0;
}
inline bool check(int l)
{
	int tot=1;
	for (int i=1;i<N;i++)
		if (suffixArray::height[i]>=l)
		{
			if (++tot>=K)
				return true;
		}
		else
			tot=1;

	return false;
}
inline int search()
{
	int L=0, R=N, M;

	while (L+1<R)
	{
		M=(L+R)>>1;
		if (check(M)) L=M;
		else R=M;
	}

	return L;
}

 

机房里把 插入代码(推荐) 给卡了真是 sang xin bing kuang!我要申诉!

posted on 2014-08-22 18:44  dyllalala  阅读(248)  评论(1编辑  收藏  举报