[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!我要申诉!

你可能感兴趣的:(Pattern)