zoukankan      html  css  js  c++  java
  • 【POJ1743】Musical Theme(后缀数组)

    【POJ1743】Musical Theme(后缀数组)

    题面

    洛谷,这题是弱化版的,(O(n^2)dp)能过
    hihoCoder 有一点点区别
    POJ 多组数据

    题解

    要求的是最长不可重叠重复子串
    也就是找两个最长的相同子串
    使得它们不相交

    先求出(SA,height)
    考虑一下如果两个子串相同
    那么也就是两个后缀的前缀相同

    还是一样吧。
    二分答案,长度为(K)
    那么,现在要找的就是连续长度不小于(K)(height)
    如果一段连续的(height)都不小于(K)
    证明这段区间的任意两个后缀的(LCP)长度都不小于(K)

    因为要不相交
    所以记录一下这段区间的(SA)最大值和最小值
    这样就很容易的检查是否存在相交的情况
    直接二分一下就好啦


    当然了(POJ)和洛谷的题目没有这么直接
    现在存在一个"转调"的问题
    但是,不管怎么转
    相邻的差是不会变的
    所以相邻的两个求一下差再来做就行了

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define MAX 120000
    inline int read()
    {
    	int x=0,t=1;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=-1,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return x*t;
    }
    int SA[MAX],x[MAX],y[MAX],t[MAX];
    int Rank[MAX],height[MAX];
    int n,a[MAX];
    bool cmp(int i,int j,int k){return y[i]==y[j]&&y[i+k]==y[j+k];}
    void GetSA()
    {
    	int m=1500;
    	for(int i=1;i<=n;++i)t[x[i]=a[i]]++;
    	for(int i=1;i<=m;++i)t[i]+=t[i-1];
    	for(int i=n;i>=1;--i)SA[t[x[i]]--]=i;
    	for(int k=1;k<=n;k<<=1)
    	{
    		int p=0;
    		for(int i=n-k+1;i<=n;++i)y[++p]=i;
    		for(int i=1;i<=n;++i)if(SA[i]>k)y[++p]=SA[i]-k;
    		for(int i=0;i<=m;++i)t[i]=0;
    		for(int i=1;i<=n;++i)t[x[y[i]]]++;
    		for(int i=1;i<=m;++i)t[i]+=t[i-1];
    		for(int i=n;i>=1;--i)SA[t[x[y[i]]]--]=y[i];
    		swap(x,y);
    		x[SA[1]]=p=1;
    		for(int i=2;i<=n;++i)
    			x[SA[i]]=cmp(SA[i],SA[i-1],k)?p:++p;
    		if(p>=n)break;
    		m=p;
    	}
    	for(int i=1;i<=n;++i)Rank[SA[i]]=i;
    	for(int i=1,j=0;i<=n;++i)
    	{
    		if(j)j--;
    		while(a[i+j]==a[SA[Rank[i]-1]+j])++j;
    		height[Rank[i]]=j;
    	}
    }
    bool check(int k)
    {
    	int mm,mi;
    	for(int i=1;i<=n;++i)
    	{
    		if(height[i]<k)
    			mm=mi=SA[i];
    		else
    		{
    			mi=min(mi,SA[i]);
    			mm=max(mm,SA[i]);
    			if(mm-mi>k)return true;
    		}
    	}
    	return false;
    	
    }
    int main()
    {
    	while(233)
    	{
    		n=read();
    		if(!n)break;
    		memset(SA,0,sizeof(SA));
    		memset(height,0,sizeof(height));
    		memset(Rank,0,sizeof(Rank));
    		memset(x,0,sizeof(x));memset(y,0,sizeof(y));
    		memset(t,0,sizeof(t));memset(a,0,sizeof(a));
    		for(int i=1;i<=n;++i)a[i]=read();
    		for(int i=1;i<=n;++i)a[i]=a[i+1]-a[i]+100;
    		GetSA();
    		int l=1,r=n,ans=0;
    		while(l<=r)
    		{
    			int mid=(l+r)>>1;
    			if(check(mid))l=mid+1,ans=mid;
    			else r=mid-1;
    		}
    		printf("%d
    ",ans>=4?ans+1:0);
    	}
    }
    
    
  • 相关阅读:
    微信支付授权目录填写规则
    前后端分离之vue2.0+webpack2 实战项目 -- html模板拼接
    前后端分离之vue2.0+webpack2 实战项目 -- webpack介绍
    windows下nginx的安装及使用方法入门
    抛弃vue-resource拥抱axios
    Eslint检测出的问题如何自动修复
    用webpack2.0构建vue2.0单文件组件超级详细精简实例
    SQLAlchemy 教程 —— 基础入门篇
    Linux下python2.7安装pip
    python 创建虚拟环境(virtualenv)
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8336878.html
Copyright © 2011-2022 走看看