zoukankan      html  css  js  c++  java
  • codeforces 232D. Fence

    传送门: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
    ",h[i]);
    	//for (int i=1;i<=N;i++) printf("rank%d
    ",rank[i]);
    	for (int l,r;Q;Q--){
    		scanf("%d%d",&l,&r);
    		if (l==r) printf("%d
    ",n-1);
    		else printf("%d
    ",query(l,r));
    	}
    	return 0;
    }


  • 相关阅读:
    20200311 1. 消息中间件概述
    20200311 0. RabbitMQ 安装
    20210309 java.lang.Integer
    20210304. Redis【归档】
    20210304. 8. Redis 大厂面试汇总
    20210304. 7. Redis 企业实战
    20210304. 6. Redis 高可用方案
    20210304. 5. Redis 扩展功能
    Evolution Strategies as a Scalable Alternative to Reinforcement Learning
    脉冲神经网络研究现状及展望——论文摘抄
  • 原文地址:https://www.cnblogs.com/thythy/p/5493535.html
Copyright © 2011-2022 走看看