zoukankan      html  css  js  c++  java
  • 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/2);
                continue;
            }
            printf("%d
    ",work(x,y-1));
        }
        return 0;
    }
  • 相关阅读:
    jQuery EasyUI API 中文文档 数字框(NumberBox)
    jQuery EasyUI API 中文文档 数值微调器(NumberSpinner)
    jQuery EasyUI API 中文文档 日期时间框(DateTimeBox)
    jQuery EasyUI API 中文文档 微调器(Spinner)
    jQuery EasyUI API 中文文档 树表格(TreeGrid)
    jQuery EasyUI API 中文文档 树(Tree)
    jQuery EasyUI API 中文文档 属性表格(PropertyGrid)
    EntityFramework 数据操作
    jQuery EasyUI API 中文文档 对话框(Dialog)
    jQuery EasyUI API 中文文档 组合表格(ComboGrid)
  • 原文地址:https://www.cnblogs.com/harden/p/6597046.html
Copyright © 2011-2022 走看看