給出n個1-88組成的音符,讓找出一個最長的連續子序列,知足如下條件:c++
咱們處理一下這個所謂的「變調」:令\(a[i]=a[i+1]-a[i]\),這樣就轉化成了找最長的出現至少兩次的不重疊子串。(這時長度變爲n-1)數組
兩種作法:1.二分+ hash 2. 二分+後綴數組工具
使用hash的時候,對於當前二分的長度x。spa
咱們從x開始遍歷到n,若是[i-x+1,i]的hash值已經出如今i-x以前過,當前長度就能夠,由於這個hash值是unsigned long long 範圍,咱們要使用map來判斷,而後就會發現超時。code
百度時候發現,題解的map是本身寫的。排序
struct hashmap { int head[Hash],next[N],sz,f[N]; /* 使用鄰接表把%Hash相同的數字串起來 state[i]放的是具體的值 f[i]放的是值的下標 sz是存的數字的數量 */ ull state[N]; void init() { sz=0; memset(head,-1,sizeof(head)); } int add(ull val,int id) { int now=val%Hash; for(int i=head[now]; i!=-1; i=next[i]) { if(val==state[i])//val已經出現過,返回第一次出現的下標 return f[i]; } /*val沒有出現,加入到hashmap中*/ state[sz]=val; f[sz]=id; next[sz]=head[now]; head[now]=sz++; return f[sz-1]; } } mp;
使用後綴數組。字符串
引自[後綴數組——處理字符串的有力工具]----羅穗騫get
先二分答案,把題目變成斷定性問題:判斷是否存在兩個長度爲k的子串是相同的,且不重疊。解決這個問題的關鍵仍是利用height數組。把排序後的後綴分紅若干組,其中每組的後綴之間的height值都不小於k。例如,字符串爲「aabaaaab」,當k=2時,後綴分紅了4組,如圖所示。string
容易看出,有但願成爲最長公共前綴不小於k的兩個後綴必定在同一組。而後對於每組後綴,只須判斷每一個後綴的sa值的最大值和最小值之差是否不小於k。若是有一組知足,則說明存在,不然不存在。整個作法的時間複雜度爲O(nlogn)。本文中利用height值對後綴進行分組的方法很經常使用,請讀者認真體會hash
// #include <bits/stdc++.h> #include<stdio.h> #include<algorithm> #include<string.h> #define pb push_back using namespace std; typedef long long ll; typedef unsigned long long ull; const int N = 1e5 + 10; const int mod = 1e9 + 7; const int inf = 0x3f3f3f3f; int cnt[N],oldrk[N],rk[N],sa[N],pos[N],ht[N]; int n,m; int arr[N]; bool cmp(int x,int y,int k) { return oldrk[x]==oldrk[y]&&oldrk[x+k]==oldrk[y+k]; } void getsa() { memset(cnt,0,sizeof(cnt)); m=200; for(int i=1; i<=n; i++) ++cnt[rk[i]=arr[i]]; for(int i=1; i<=m; i++) cnt[i]+=cnt[i-1]; for(int i=n; i; i--) sa[cnt[rk[i]]--]=i; for(int k=1; k<=n; k<<=1) { int num=0; for(int i=n-k+1; i<=n; i++) pos[++num]=i; for(int i=1; i<=n; i++) { if(sa[i]>k) pos[++num]=sa[i]-k; } memset(cnt,0,sizeof(cnt)); for(int i=1; i<=n; i++) ++cnt[rk[i]]; for(int i=1; i<=m; i++) cnt[i]+=cnt[i-1]; for(int i=n; i; i--) sa[cnt[rk[pos[i]]]--]=pos[i]; num=0; memcpy(oldrk,rk,sizeof(rk)); for(int i=1; i<=n; i++) rk[sa[i]]=cmp(sa[i],sa[i-1],k)?num:++num; if(m==n) break; m=num; } for(int i=1; i<=n; i++) rk[sa[i]]=i; int k=0; for(int i=1; i<=n; i++) { if(k) --k; while(arr[i+k]==arr[sa[rk[i]-1]+k]) ++k; ht[rk[i]]=k; } } int judge(int x) { int minn=sa[1],maxn=sa[1]; for(int i=2; i<=n; i++)//精闢 { if(ht[i]>=x) { maxn=max(maxn,sa[i]); minn=min(minn,sa[i]); } else { minn=sa[i]; maxn=sa[i]; } if(maxn-minn>x) return 1; } return 0; } int main() { while(~scanf("%d",&n)&&n) { for(int i=1; i<=n; i++) scanf("%d",&arr[i]); for(int i=1; i<n; i++) arr[i]=arr[i+1]-arr[i]+100; n--; getsa(); int l=4,r=n/2,ans=0; while(l<=r) { int mid=(l+r)/2; if(judge(mid)) { ans=mid; l=mid+1; } else r=mid-1; } if(!ans) printf("0\n"); else printf("%d\n",ans+1); } return 0; }
#include<algorithm> #include<stdio.h> #include<string.h> #include<map> #define pb push_back using namespace std; typedef long long ll; typedef unsigned long long ull; const int N = 2e4 + 10; const int mod = 1610612741; const int inf = 0x3f3f3f3f; const int Hash=10007; ull hash1[N],bin[N]; int n,arr[N],brr[N]; ull get(int l,int r) { return hash1[r]-hash1[l-1]*bin[r-l+1]; } struct hashmap { int head[Hash],next[N],sz,f[N]; ull state[N]; void init() { sz=0; memset(head,-1,sizeof(head)); } int add(ull val,int id) { int now=val%Hash; for(int i=head[now]; i!=-1; i=next[i]) { if(val==state[i]) return f[i]; } state[sz]=val; f[sz]=id; next[sz]=head[now]; head[now]=sz++; return f[sz-1]; } } mp; int judge(int x) { mp.init(); for(int i=x; i<n; i++) { if(mp.add(get(i-x+1,i),i)<i-x) return 1; } return 0; } int main() { bin[0]=1; for(int i=1; i<=20000; i++) bin[i]=bin[i-1]*137; while(~scanf("%d",&n)&&n) { for(int i=1; i<=n; i++) scanf("%d",&arr[i]); for(int i=1;i<n;i++) { arr[i]=arr[i+1]-arr[i]; hash1[i]=hash1[i-1]*137+arr[i]; } int l=4,r=n/2-1,ans=0; while(l<=r) { int mid=(l+r)/2; if(judge(mid)) { ans=mid; l=mid+1; } else r=mid-1; } if(!ans) printf("0\n"); else printf("%d\n",ans+1); } return 0; }