zoukankan      html  css  js  c++  java
  • POJ 1743 Musical Theme

    Description

    一个数列求对应差相等最长的一段。(nleqslant 2 imes 10^4)

    Solution

    后缀数组+二分。

    将数列差分一下,一段字符串在(height)数组上一定是连续的一段,二分一个答案,找到一段(>=mid)的区间,然后记录一下最大最小值。

    因为(mid)会将他们分成一段段区间,最后判断一下即可。

    Code

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    
    const int N = 20050;
    
    inline int in(int x=0,char ch=getchar()) { while(ch>'9'||ch<'0') ch=getchar();
    	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();return x; }
    
    int n,m;
    int a[N],b[N];
    
    namespace SA {
    	int t1[N],t2[N],c[N],sa[N],rk[N],ht[N];
    	
    	void clear() {
    		memset(sa,0,sizeof(sa));
    		memset(rk,0,sizeof(rk));
    		memset(ht,0,sizeof(ht));
    	}
    	void get_sa(int a[],int n=::n,int m=::m) {
    		int *x=t1,*y=t2;
    		for(int i=1;i<=m;i++) c[i]=0;
    		for(int i=1;i<=n;i++) c[x[i]=a[i]]++;
    		for(int i=1;i<=m;i++) c[i]+=c[i-1];
    		for(int i=n;i;--i) sa[c[x[i]]--]=i;
    		for(int k=1,p=0;k<n;k<<=1,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=1;i<=m;i++) c[i]=0;
    			for(int i=1;i<=n;i++) c[x[i]]++;
    			for(int i=1;i<=m;i++) c[i]+=c[i-1];
    			for(int i=n;i;--i) sa[c[x[y[i]]]--]=y[i];
    			swap(x,y),x[sa[1]]=p=1;
    			for(int i=2;i<=n;i++) 
    				x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?p:++p;
    			if(p>=n) break;m=p;
    		}
    	}
    	void get_ht(int a[],int n=::n) {
    		for(int i=1;i<=n;i++) rk[sa[i]]=i;
    		for(int i=1,j,k=0;i<=n;ht[rk[i++]]=k)
    			for(j=sa[rk[i]-1],k=k?k-1:k;a[i+k]==a[j+k];k++);
    	}
    }
    
    using namespace SA;
    
    int chk(int x) {
    	for(int i=1,j;i<=n;i=j) {
    		int mi=n,mx=0;
    		if(ht[i]<x) { j=i+1;continue; }
    		mi=min(mi,sa[i-1]),mx=max(mx,sa[i-1]);
    		for(j=i;j<=n && ht[j]>=x;mi=min(mi,sa[j]),mx=max(mx,sa[j]),j++);
    		if(mi+x<=mx) return 1;
    	}return 0;
    }
    
    void Solve() {
    	int l=0,r=n;
    	for(;l<=r;) {
    		int mm=(l+r)>>1;
    		if(chk(mm)) l=mm+1;
    		else r=mm-1;
    	}printf("%d
    ",r>3?r+1:0);
    }
    
    int main() {
    	for(;;) {
    		if(!(n=in())) break;
    		for(int i=1;i<=n;i++) b[i]=in();
    		for(int i=1;i<n;i++) a[i]=b[i+1]-b[i]+100;
    		n--;
    //		n=in();
    //		for(int i=1;i<=n;i++) a[i]=in();
    //		for(int i=1;i<=n;i++) cout<<a[i]<<" ";cout<<endl;
    		clear();
    		get_sa(a,n,200);
    //		cout<<"qwq"<<endl;
    //		for(int i=1;i<=n;i++) cout<<sa[i]<<" ";cout<<endl;
    		get_ht(a,n);
    //		for(int i=1;i<=n;i++) cout<<ht[i]<<" ";cout<<endl;
    		Solve();
    	}return 0;
    }
    

      

  • 相关阅读:
    关于gtk的GCond
    位运算符及其应用
    登陆新浪微博&批量下载收藏内容[Python脚本实现]
    海量数据处理算法—Bloom Filter
    海量数据处理算法—BitMap
    VB.NET机房收费系统——组合查询
    非官方的gstreamer学习资料及概念摘要
    [Python入门及进阶笔记00]写在前面(目录/书籍/学习路线/其他)
    [JAVA][Eclipse]JVM terminated. Exit code=13
    介绍一个android开源文件选择对话框:androidfiledialog
  • 原文地址:https://www.cnblogs.com/beiyuoi/p/6646324.html
Copyright © 2011-2022 走看看