P2743(poj1743) Musical Themes[差分+后缀数组]

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\n",ans?ans+1:0);
54     return 0;
55 }

猜你喜欢

转载自www.cnblogs.com/saigyouji-yuyuko/p/10344549.html