http://codeforces.com/problemset/problem/232/D
给你一个长度为n 的序列A,有定两个值L1,S,求L2,满足:
1.[L1,L1+s??1]和[L2,L2+s??1]不相交,均在[1,n]内。
2.对于任意0<k<s,有Bk=A[L1+k]+A[L2+k],要求所有Bk相等。
有Q 组询问,对于给定的L1和s,有多少L2 满足要求。
看起来并不是字符串题,但是却可以转化啊囧。
条件可以看成是这样的:
对于0<i<s,A[l1+i]+A[l2+i]=A[l1+i-1]+A[l2+i-1]。
移项,得到A[l1+i]-A[l1+i-1]=A[l2+i-1]-A[l2+i]。
那不就可以看成这个数组的差分数组和差分数组中每一项取相反数得到的数组的长度为S的公共子串吗?(当然还有条件1的限制)
对于每次询问,我们找到l1起始的后缀的排名,即rank[l1],向上向下二分出lcp(up,low)≥S的区间,然后相当于在这个区间中查询满足[sa[i],sa[i]+s-1]不与[l1,l1+s-1]相交的后缀的个数。用可持久化线段树查询即可。
#include<bits/stdc++.h> using namespace std; const int maxn=100015; vector<int> w; int n,q,len,s[maxn],p[maxn<<1]; struct Tsegment{ static const int maxn=::maxn<<1,maxk=20; int tot,L,R; struct Tnode{ Tnode *c[2];int siz; }*root[maxn],T[maxn*maxk]; void clear(int l,int r){ L=l;R=r;tot=0;root[0]=T;root[0]->siz=0; root[0]->c[0]=root[0]->c[1]=root[0]; } Tnode *newnode(Tnode *x){ Tnode *cur=T+(++tot); *cur=*x;return cur; } void modify(Tnode *ever,Tnode *&now,int l,int r,int x){ now=newnode(ever);++now->siz; int mid=(l+r)>>1;if (l==r) return; if (x<=mid) modify(ever->c[0],now->c[0],l,mid,x); else modify(ever->c[1],now->c[1],mid+1,r,x); } int query(Tnode *ever,Tnode *now,int l,int r,int a,int b){ if (l==a&&r==b) return now->siz-ever->siz; if (a>b) return 0;int mid=(l+r)>>1; if (b<=mid) return query(ever->c[0],now->c[0],l,mid,a,b); else if (a>=mid+1) return query(ever->c[1],now->c[1],mid+1,r,a,b); else return query(ever->c[0],now->c[0],l,mid,a,mid)+query(ever->c[1],now->c[1],mid+1,r,mid+1,b); } void modify(int ever,int now,int x){modify(root[ever],root[now],L,R,x);} int query(int ever,int now,int a,int b){return query(root[ever],root[now],L,R,a,b);} }segment; struct Tsuffix_array{ static const int maxn=::maxn<<1,maxk=20; int sum[maxn],sa[maxn],rank[maxn],tsa[maxn],trank[maxn]; bool cmp(int i,int j,int l){ if (i+l>len||j+l>len) return 0; return rank[i]==rank[j]&&rank[i+l]==rank[j+l]; } void suffix_sort(int s[]){ int m=len,p,i,j; for (i=0;i<=m;++i) sum[i]=0; for (i=1;i<=len;++i) ++sum[rank[i]=s[i]]; for (i=1;i<=m;++i) sum[i]+=sum[i-1]; for (i=len;i>=1;--i) sa[sum[rank[i]]--]=i; for (j=1,p=0;p<len;j<<=1,m=p){ for (p=0,i=len-j+1;i<=len;++i) tsa[++p]=i; for (i=1;i<=len;++i) if (sa[i]>j) tsa[++p]=sa[i]-j; for (i=0;i<=m;++i) sum[i]=0; for (i=1;i<=len;++i) ++sum[rank[tsa[i]]]; for (i=1;i<=m;++i) sum[i]+=sum[i-1]; for (i=len;i>=1;--i) sa[sum[rank[tsa[i]]]--]=tsa[i]; for (p=trank[sa[1]]=1,i=2;i<=len;++i) trank[sa[i]]=cmp(sa[i],sa[i-1],j)?p:++p; memcpy(rank,trank,sizeof(int)*(len+1)); } } int height[maxn]; void get_height(int s[]){ for (int h=0,i=1;i<=len;++i){ if (rank[i]==1) continue; for (h?--h:0;s[i+h]==s[sa[rank[i]-1]+h];++h); height[rank[i]]=h; } } int fmn[maxk][maxn]; void prepare(){ for (int i=1;i<=len;++i) fmn[0][i]=height[i]; for (int k=1;k<maxk;++k) for (int i=1<<k;i<=len;++i) fmn[k][i]=min(fmn[k-1][i],fmn[k-1][i-(1<<(k-1))]); segment.clear(1,len); for (int i=1;i<=len;++i) segment.modify(i-1,i,sa[i]); } int lcp(int l,int r){ if (++l>r) return len-sa[r]+1; int k=log2(r-l+1); return min(fmn[k][r],fmn[k][l+(1<<k)-1]); } int calc_up(int pos,int lim){ int l=1,r=pos,res; while (l<=r){ int mid=(l+r)>>1; lcp(mid,pos)>=lim?r=(res=mid)-1:l=mid+1; } return res; } int calc_low(int pos,int lim){ int l=pos,r=len,res; while (l<=r){ int mid=(l+r)>>1; lcp(pos,mid)>=lim?l=(res=mid)+1:r=mid-1; } return res; } int query(int l,int r){ int length=r-l; int up=calc_up(rank[l],length),low=calc_low(rank[l],length); l+=n;r+=n; return segment.query(up-1,low,n+1,l-length-1)+segment.query(up-1,low,r+1,len); } }SA; void init(){ scanf("%d",&n);len=(n<<1)-1;p[n]=2e9+1; for (int i=1;i<=n;++i) scanf("%d",&s[i]); for (int i=2;i<=n;++i){p[i-1]=s[i]-s[i-1];p[n+i-1]=s[i-1]-s[i];} for (int i=1;i<=len;++i) w.push_back(p[i]); sort(w.begin(),w.end());w.erase(unique(w.begin(),w.end()),w.end()); for (int i=1;i<=len;++i) p[i]=lower_bound(w.begin(),w.end(),p[i])-w.begin()+1; } void work(){ SA.suffix_sort(p);SA.get_height(p); SA.prepare();scanf("%d",&q); for (int l,r,i=1;i<=q;++i){ scanf("%d%d",&l,&r); if (l==r) printf("%d\n",n-1); else printf("%d\n",SA.query(l,r)); } } int main(){ init(); work(); return 0; }
my code
时间: 2024-10-20 00:29:05