zoukankan      html  css  js  c++  java
  • POJ3261-Milk Patterns(后缀数组)

    题意:给定一个整数序列,求这个整数序列中至少重复出现K次的子串的最大长度。

    分析:我们求出lcp[]数组:相邻后缀的最长公共前缀,我们二分长度,然后判断是否存在一段连续的一组的长度>=二分的长度,并且至少存在k次。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <vector>
    #include <queue>
    #include <algorithm>
    
    using namespace std;
    const int N = 20005;
    int k;
    int rk[N], tmp[N];
    int sa[N], lcp[N];
    int a[N];
    int n, K;
    bool compare_sa(int i, int j)
    {
    	if (rk[i] != rk[j]) return rk[i] < rk[j];
    	else
    	{
    		int ri = i + k <= n ? rk[i + k] : -1;
    		int rj = j + k <= n ? rk[j + k] : -1;
    		return ri < rj;
    	}	
    }
    
    void construct_sa(int a[], int sa[])
    {
    	for (int i = 0; i <= n; ++i)
    	{
    		sa[i] = i;
    		rk[i] = i < n ? a[i] : -1;
    	}
    	for (k = 1; k <= n; k *= 2)
    	{
    		sort(sa, sa + n + 1, compare_sa);
    		tmp[sa[0]] = 0;
    		for (int i = 1; i <= n; ++i)
    			tmp[sa[i]] = tmp[sa[i - 1]] + (compare_sa(sa[i - 1], sa[i]) ? 1 : 0);
    		for (int i = 0; i <= n; ++i)
    			rk[i] = tmp[i];
    	}
    }
    
    void construct_lcp(int a[], int sa[], int lcp[])
    {
    	for (int i = 0; i <= n; ++i) rk[sa[i]] = i;
    
    	int h = 0;
    	lcp[0] = 0;
    
    	for (int i = 0; i < n; ++i)
    	{
    		int j = sa[rk[i] - 1];
    
    		if (h > 0) --h;
    		for (; j + h < n && i + h < n; ++h)
    		{
    			if (a[j + h] != a[i + h]) break;
    		}
    		lcp[rk[i] - 1] = h;
    	}
    }
    
    bool check(int mid)
    {
    	int tot = 1;
    	for (int i = 0; i < n; ++i)
    	{
    		if (lcp[i] >= mid)
    			++tot;
    		else
    		{
    			if (tot >= K)
    				return true;
    			else
    				tot = 1;
    		}
    	}
    	return tot >= K;
    }
    
    int main()
    {	
    	scanf("%d%d", &n, &K);
    
    	for (int i = 0; i < n; ++i) scanf("%d", &a[i]);
    
    	construct_sa(a, sa);
    	construct_lcp(a, sa, lcp);
    
    	int l = 0, r = n;
    
    	while (l < r)
    	{
    		int mid = l + r + 1 >> 1;
    		if (check(mid)) l = mid;
    		else r = mid - 1;
    	}
    
    	printf("%d
    ", l);
    
    
    	return 0;
    }
    

  • 相关阅读:
    VS.NET2005中的源代码管理
    IE6升级后需要激活ActiveX控件的解决办法
    SQL Server的数据库开发工具
    今天更新了ActiveSync4.2
    永远等你先挂电话
    这回软设考试通过了!
    在Windows2003中FSO组件不能使用的问题
    七天的假期好长哟!
    发现博客园的一个Bug 存为草稿后就找不到了
    MySQL服务不能启动的解决方法
  • 原文地址:https://www.cnblogs.com/pixel-Teee/p/13372726.html
Copyright © 2011-2022 走看看