P2743 乐曲主题Musical Themes(poj1743)
然后呢这题思路其实还是蛮简单的,只是细节特别多比较恶心,忘记了差分带来的若干疏漏。
因为转调的话要保证找到相同主题,只要保证一段内相对的差值不变,所以自然而然想到差分。
注意细节。
1.因为差分会带来负数,而负数在后缀数组里最初排名是会出问题的,所以要全搞成正的,+100即可
2.因为最后一位不可以计算入差分数组里,所以不算,n要减1,同时二分答案后要记得
把求得的最长差分长度加上一才是原数组长度
3.最坑的地方是找不重复的最长字串,自然套路二分答案,但check时有部分不一样。
因为差分会导致下标相减算原串长度出问题,所以要注意,具体看check函数。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=5000+7; 5 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;} 6 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;} 7 inline int read(){ 8 int x=0,f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1; 9 while(isdigit(c))x=(x<<1)+(x<<3)+(c^48),c=getchar();return f?-x:x; 10 } 11 int A[N],a[N],sa[N],rk[N],x[N],y[N],cnt[N],h[N]; 12 int n,m=200,p,L,R,mid,ans; 13 14 inline void suffix_sort(){ 15 for(register int i=1;i<=n;++i)++cnt[x[i]=a[i]]; 16 for(register int i=1;i<=m;++i)cnt[i]+=cnt[i-1]; 17 for(register int i=n;i;--i)sa[cnt[x[i]]--]=i; 18 for(register int k=1;k<n;k<<=1,p=0){ 19 for(register int i=n-k+1;i<=n;++i)y[++p]=i; 20 for(register int i=1;i<=n;++i)if(sa[i]>k)y[++p]=sa[i]-k; 21 for(register int i=1;i<=m;++i)cnt[i]=0; 22 for(register int i=1;i<=n;++i)++cnt[x[y[i]]]; 23 for(register int i=1;i<=m;++i)cnt[i]+=cnt[i-1]; 24 for(register int i=n;i;--i)sa[cnt[x[y[i]]]--]=y[i]; 25 swap(x,y);x[sa[1]]=p=1; 26 for(register 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; 27 if(p==n)break;m=p; 28 }p=0; 29 for(register int i=1;i<=n;++i)rk[i]=x[i]; 30 for(register int i=1;i<=n;h[rk[i]]=p,p?--p:1,++i)while(a[i+p]==a[sa[rk[i]-1]+p]&&++p); 31 } 32 33 inline int check(int k){ 34 int l=sa[1],r=sa[1]; 35 for(register int i=2;i<=n;++i){ 36 if(h[i]<k)l=r=sa[i]; 37 else{MIN(l,sa[i]),MAX(r,sa[i]);if(r-l>k)return 1;} 38 } 39 return 0; 40 } 41 42 int main(){//freopen("tmp.in","r",stdin); 43 n=read();L=4,R=n/2+1; 44 if(n<10){cout<<0<<endl;return 0;} 45 for(register int i=1;i<=n;++i)A[i]=read(); 46 for(register int i=1;i<n;++i)a[i]=A[i+1]-A[i]+100;--n; 47 suffix_sort(); 48 while(L<=R){ 49 mid=L+R>>1; 50 if(check(mid))L=mid+1,ans=mid; 51 else R=mid-1;//cerr<<mid<<" "<<check(mid)<<endl; 52 } 53 printf("%d ",ans?ans+1:0); 54 return 0; 55 }