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;
    }
  • 相关阅读:
    ANSI编码和Unicode编码的不同[转]
    [bash script]改进版目录和文件显示
    [bash script] Typed Variables
    六年了,留几句话吧
    读点书吧
    如果MFC的消息映射表需要排序...
    谈谈我们的开发流程
    寻找总和为n的连续子数列之算法分析
    在Windows下编译FreeCAD
    给定一个数组,找出不在数组中的最小的那个数字
  • 原文地址:https://www.cnblogs.com/harden/p/6597046.html
Copyright © 2011-2022 走看看