zoukankan      html  css  js  c++  java
  • 「Luogu2743/POJ1743」[USACO5.1]乐曲主题Musical Themes

    「Luogu2743/POJ1743」[USACO5.1]乐曲主题Musical Themes

    Luogu
    Poj

    两个OJ题号的LCS长度为3

    Solution

    洛谷这边(N)的范围是(5000),哈希可以过

    但是在POJ就到了(20000),而且是多组数据,哈希似乎是过不了了

    这里写一下用后缀数组的一个比较妙的做法


    首先,对于转调的情况,我们很容易想到可以对原数组进行差分

    然后做(SA),求出差分数组的(height)

    显然答案可以二分,我们二分答案(mid),然后将(height)数组分成若干段。对于每一段(height[x])(height[y]),满足(height[x+1])(height[y])均大于等于(mid)

    我们知道,对于两个后缀(x,y)(lcp(x,y)=min{height[rank[x+1]],height[rank[x+2]],dots,height[rank[y]]})

    所以在每一段中,任意两个被划分到同一段的后缀的(lcp)长度都是大于等于(mid)

    那么在每一段内,若存在一对((i,j))满足(sa[j]-sa[i]>mid),那么这个(mid)就是合法的

    长度不小于(5)可以通过调整二分的下界进行限制

    需要注意的是我们是对差分数组进行处理,所以原序列的子串的长度(=)对应差分序列子串长度(+1)

    Code

    这里放的是(POJ)(AC)代码

    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    #include <cstring>
    #include <iostream>
    using namespace std;
    typedef long long ll;
    
    template <typename T>void read(T &t)
    {
    	t=0;int f=0;char c=getchar();
    	while(!isdigit(c)){f|=c=='-';c=getchar();}
    	while(isdigit(c)){t=t*10+c-'0';c=getchar();}
    	if(f)t=-t;
    }
    
    const int maxn=20000+5;
    int n,m;
    int det[maxn];
    int sa[maxn],rnk[maxn],tp[maxn];
    
    int c[maxn];
    void Sort()
    {
    	for(register int i=0;i<=m;++i)c[i]=0;
    	for(register int i=1;i<=n;++i)c[rnk[i]]++;
    	for(register int i=1;i<=m;++i)c[i]+=c[i-1];
    	for(register int i=n;i;--i)sa[c[rnk[tp[i]]]--]=tp[i];
    }
    
    int height[maxn];
    void GetHeight()
    {
    	for(register int i=1;i<=n;++i)rnk[i]=det[i],tp[i]=i;
    	Sort();
    	for(register int w=1,p=0;p<n;m=p,w<<=1)
    	{
    		p=0;
    		for(register int i=1;i<=w;++i)tp[++p]=n-w+i;
    		for(register int i=1;i<=n;++i)if(sa[i]>w)tp[++p]=sa[i]-w;
    		Sort();
    		swap(tp,rnk);
    		rnk[sa[1]]=1,p=1;
    		for(register int i=2;i<=n;++i)
    			rnk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]] && tp[sa[i]+w]==tp[sa[i-1]+w])?p:++p;
    	}
    	for(register int i=1,k=0;i<=n;++i)
    	{
    		if(k)--k;
    		int j=sa[rnk[i]-1];
    		while(det[i+k]==det[j+k])++k;
    		height[rnk[i]]=k;
    	}
    }
    
    bool Check(int len)
    {
    	int xx;
    	for(register int i=1;i<=n;i=xx+1)
    	{
    		xx=i;
    		while(height[xx+1]>=len)++xx;
    		int mn=0x3f3f3f3f,mx=0;
    		for(register int j=i;j<=xx;++j)
    		{
    			mn=min(mn,sa[j]);
    			mx=max(mx,sa[j]);
    		}
    		if(mx-mn>len)return true;
    	}
    	return false;
    }
    
    int main()
    {
    	while(scanf("%d",&n),n)
    	{
    		m=88*2;
    		for(register int i=1,last=0;i<=n;++i)
    		{
    			int x;
    			read(x);
    			det[i]=x-last+88;//防止出现负数
    			last=x;
    		}
    		GetHeight();
    		register int l=4,r=n-1,ans=-1;
    		while(l<=r)
    		{
    			int mid=(l+r)>>1;
    			if(Check(mid))
    				ans=mid,l=mid+1;
    			else
    				r=mid-1;
    		}
    		printf("%d
    ",ans+1);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Spring Cloud Config微服务高可用配置中心配置
    SpringCloud系列教程带实操
    小白入门~ GitHub和Git超详细使用教程~~~
    (转)统一建模语言UML用法
    (转)理解Java对象的序列化和反序列化
    Intellij IDEA如何自动生成一个serialVersionUI
    枚举的特性梳理
    java实操题:一个数组有100个元素,每次移除该数组第7的整数倍元素......
    利用vertical-align属性实现分隔符
    css指示箭头两种实现方法
  • 原文地址:https://www.cnblogs.com/lizbaka/p/10664399.html
Copyright © 2011-2022 走看看