Fence(codeforces 232D)
题意:
对于给定的a[1..n],定义区间[s,t]和[x,y]"匹配"当且仅当下列条件同时满足:
1. t-s=y-x,即长度相同。
3. t<x或s>y,即两区间没有交。
2. 对任0<=i<=t-s,有a[s]+a[x]=a[s+i]+a[x+i]。
现给出a[1..n]和Q个询问(x,y),求与[x,y]匹配的区间的个数。
/* 写了n个小时,还没有调出来,Orz... 代码量倒是不大,但是细节巨多,已经弃疗了。。。 先差分一下, 然后题目就变成了,也就是这段区间取相反数之后可以与原区间匹配。 设当前询问为(x,y),把整个串取相反数,再复制到后面,用后缀数组向上向下二分出可行区间。 然后要求不可重叠,就是求rank在(l,r)中有多少串的位置在一个区间内,用主席树搞一搞。 */ #include<cstdio> #include<iostream> #include<algorithm> #define N 200010 using namespace std; int id[N],a[N],b[N],s[N],t1[N],t2[N],c[N],sa[N],rank[N],height[N],n; int lg2[N],st[N][20],sum[N*11],son[N*11][2],root[N],cnt; struct node{ int x,num; bool operator<(const node&s1)const{ if(x==s1.x) return num<s1.num; return x<s1.x; } }r[N]; bool cmp(int *y,int a,int b,int k){ int a1=y[a],b1=y[b]; int a2=a+k<=n?y[a+k]:-1; int b2=b+k<=n?y[b+k]:-1; return a1==b1&&a2==b2; } void DA(){ int *x=t1,*y=t2,m=1; for(int i=1;i<=n;i++) r[i]=(node){s[i],i}; sort(r+1,r+n+1); for(int i=1;i<=n;i++) sa[i]=r[i].num; x[sa[1]]=1; for(int i=2;i<=n;i++) x[sa[i]]=r[i].x==r[i-1].x?m:++m; for(int k=1,p=0;k<=n;k*=2,m=p,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[y[i]]]++; for(int i=2;i<=m;i++) c[i]+=c[i-1]; for(int i=n;i;i--) sa[c[x[y[i]]]--]=y[i]; swap(x,y);p=1;x[sa[1]]=1; for(int i=2;i<=n;i++) if(cmp(y,sa[i-1],sa[i],k)) x[sa[i]]=p; else x[sa[i]]=++p; if(p>=n) break; } } void geth(){ for(int i=1;i<=n;i++) rank[sa[i]]=i; for(int i=1,j=0;i<=n;i++){ if(rank[i]==1) continue; while(s[i+j]==s[sa[rank[i]-1]+j]) j++; height[rank[i]]=j; if(j) j--; } for(int i=2;i<=n;i++) lg2[i]=lg2[i>>1]+1; for(int i=1;i<=n;i++) st[i][0]=height[i]; for(int j=1;(1<<j)<=n;j++) for(int i=1;i+(1<<j)-1<=n;i++) st[i][j]=min(st[i][j-1],st[i+(1<<j-1)][j-1]); } void insert(int &k,int last,int l,int r,int pos){ k=++cnt; son[k][0]=son[last][0]; son[k][1]=son[last][1]; sum[k]=sum[last]+1; if(l==r) return; int mid=l+r>>1; if(pos<=mid) insert(son[k][0],son[last][0],l,mid,pos); else insert(son[k][1],son[last][1],mid+1,r,pos); } int query(int k,int l,int r,int x,int y){ if(l>=x&&r<=y) return sum[k]; int mid=l+r>>1,tot=0; if(x<=mid) tot+=query(son[k][0],l,mid,x,y); if(y>mid) tot+=query(son[k][1],mid+1,r,x,y); return tot; } int querymn(int x,int y){ int k=lg2[y-x+1]; return min(st[x][k],st[y-(1<<k)+1][k]); } int work(int x,int y){ int pos=rank[x],l=0,r=pos,tmp1=pos,tmp2=pos; while(l<r-1){ int mid=l+r>>1; if(querymn(mid+1,pos)>=y-x+1) r=mid,tmp1=mid; else l=mid; } l=pos,r=n+1; while(l<r-1){ int mid=l+r>>1; if(querymn(pos+1,mid)>=y-x+1) l=mid,tmp2=mid; else r=mid; } int ans1=query(root[tmp2],1,n+1,x+n/2+1,y+n/2+2)-query(root[tmp1-1],1,n+1,x+n/2+1,y+n/2+2); int ans2=query(root[tmp2],1,n,1,n/2)-query(root[tmp1-1],1,n,1,n/2); return tmp2-tmp1+1-ans1-ans2; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<n;i++) s[i]=a[i+1]-a[i],s[i+n]=-s[i];s[n]=-1e9; n=n*2-1;DA();geth(); for(int i=1;i<=n;i++) insert(root[i],root[i-1],1,n,sa[i]); int Q;scanf("%d",&Q); while(Q--){ int x,y;scanf("%d%d",&x,&y); if(x==y){ printf("%d\n",n/2); continue; } printf("%d\n",work(x,y-1)); } return 0; }