codeforces 232D. Fence

来源:互联网 发布:淘宝网的商品分类 编辑:程序博客网 时间:2024/06/05 12:03

传送门:http://codeforces.com/problemset/problem/232/D

思路:首先就是差分,设d[i]=a[i+1]-a[i];

然后题目的”匹配"就可以转化为差分数组每一位的和为0

也就是这段区间取相反数之后可以与原区间匹配。

这就可以转化为字符串问题。

设当前询问为(x,y)

把整个串取相反数,再复制到后面,用后缀数组向上向下二分出可行区间(lcp(suffix(l),suffix(x))>=y-x)(注意是y-x,因为这是差分数组)

然后要求不可重叠,就是求rank在(l,r)中有多少串的位置在一个区间内。

用可持久化线段树搞一搞就可以了。

(细节巨多,写的真是想死...)

#include<cmath>#include<cstdio>#include<cstring>#include<algorithm>const int maxn=200010,maxt=maxn*20,base=1001;using namespace std;struct data{int val,id;}suf[maxn];int n,Q,N,a[maxn],b[maxn],d[maxn],sa[maxn],rank[maxn],sum[maxn],t1[maxn],t2[maxn],s[maxn],st[maxn][20],h[maxn];bool cmp(data a,data b){return a.val<b.val;}struct Per_tree{int tot,son[maxt][2],siz[maxt];void insert(int k,int p,int l,int r,int x){if (l==r){siz[k]=siz[p]+1;return;}int mid=(l+r)>>1;if (x<=mid){siz[k]=siz[p]+1,son[k][0]=++tot,son[k][1]=son[p][1];insert(son[k][0],son[p][0],l,mid,x);}else{siz[k]=siz[p]+1,son[k][1]=++tot,son[k][0]=son[p][0];insert(son[k][1],son[p][1],mid+1,r,x);}}int query(int k,int l,int r,int x,int y){if (!k) return 0;if (l==x&&r==y) return siz[k];int mid=(l+r)>>1;if (y<=mid) return query(son[k][0],l,mid,x,y);else if (x>mid) return query(son[k][1],mid+1,r,x,y);else return query(son[k][0],l,mid,x,mid)+query(son[k][1],mid+1,r,mid+1,y);}int query(int l,int r,int x,int y){return query(r,1,N,x,y)-query(l-1,1,N,x,y);}}T;void getsa(){int *x=t1,*y=t2,p=0,m=0;for (int i=1;i<=N;i++) suf[i]=(data){s[i],i};sort(suf+1,suf+1+N,cmp);for (int i=1;i<=N;i++) sa[i]=suf[i].id;x[sa[1]]=m=1;for (int i=2;i<=N;i++){if (s[sa[i]]!=s[sa[i-1]]) m++;x[sa[i]]=m;}for (int j=1;p<N;j<<=1,m=p){p=0;for (int i=N-j+1;i<=N;i++) y[++p]=i;for (int i=1;i<=N;i++) if (sa[i]>j) y[++p]=sa[i]-j;memset(sum,0,sizeof(sum));for (int i=1;i<=N;i++) sum[x[y[i]]]++;for (int i=1;i<=m;i++) sum[i]+=sum[i-1];for (int i=N;i;i--) sa[sum[x[y[i]]]--]=y[i];swap(x,y),x[sa[1]]=p=1;for (int i=2;i<=N;i++){if (y[sa[i]]!=y[sa[i-1]]||y[sa[i]+j]!=y[sa[i-1]+j]) p++;x[sa[i]]=p;}}memcpy(rank,x,sizeof(rank));}void geth(){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++;h[rank[i]]=j;if (j>0) j--;}}void prework(){T.tot=N;for (int i=1;i<=N;i++) T.insert(i,i-1,1,N,sa[i]);for (int i=1;i<=N;i++) st[i][0]=h[i];for (int i=1;i<=18;i++)for (int j=1;j+(1<<(i-1))-1<=N;j++)st[j][i]=min(st[j][i-1],st[j+(1<<(i-1))][i-1]);}int getmin(int l,int r){if (l>r) swap(l,r);int t=0; l++;if (l==r) return h[r];for (;l+(1<<t)<r;t++); if (l+(1<<t)>r) t--;return min(st[l][t],st[r-(1<<t)+1][t]);}int find(int s,int x,int op){int l,r,mid;if (op) l=s,r=N;else l=1,r=s;while (l!=r){mid=(l+r)>>1;if (op) mid++;if (getmin(mid,s)<x){if (op) r=mid-1;else l=mid+1;}else{if (op) l=mid;else r=mid;}}return l;}int query(int l,int r){int x=find(rank[l],r-l,0),y=find(rank[l],r-l,1);return T.query(x,y,n+1,n+(l-1)-(r-l))+T.query(x,y,n+(r+1),N);}int main(){scanf("%d",&n);for (int i=1;i<=n;i++) scanf("%d",&a[i]);for (int i=1;i<n;i++) d[i]=a[i+1]-a[i];for (int i=1;i<n;i++) s[i]=d[i];s[n]=-(1e9+10);for (int i=1;i<n;i++) s[i+n]=-d[i];N=(n<<1)-1;/*for (int i=1;i<n;i++) d[i]=a[i+1]-a[i];for (int i=1;i<n;i++) s[i]=d[i]+base;s[n]=1;for (int i=1;i<n;i++) s[n+i]=-d[i]+base;N=(n<<1)-1;*/getsa(),geth(),prework(),scanf("%d",&Q);//for (int i=1;i<=N;i++) printf("hhh%d\n",h[i]);//for (int i=1;i<=N;i++) printf("rank%d\n",rank[i]);for (int l,r;Q;Q--){scanf("%d%d",&l,&r);if (l==r) printf("%d\n",n-1);else printf("%d\n",query(l,r));}return 0;}


0 0