• 后缀数组


    后缀数组

    bzoj1031 JSOI字符加密Cipher

    题目大意:给一个字符串,圈成圆圈,从任意位置断开,组成len个字符串,按字典序升序排序后,输出尾字母。

    思路:将字符串加倍后,对所有后缀排序,用后缀数组的思想,O(nlogn),输出的时候只要输出长度>=len的相应位置的字母就可以了。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #define maxnode 200005
    using namespace std;
    int t1[maxnode]={0},t2[maxnode]={0},sa[maxnode]={0},cc[maxnode]={0},n,m=0;
    char ss[maxnode];
    bool cmp(int *y,int a,int b,int k)
    {
        int a2,b2;
        a2= a+k>=n ? -1 : y[a+k];
        b2= b+k>=n ? -1 : y[b+k];
        a=y[a];b=y[b];
        return a==b&&a2==b2;
    }
    void build()
    {
        int i,k,p;int *x=t1;int *y=t2;
        for (i=0;i<m;++i) cc[i]=0;
        for (i=0;i<n;++i) ++cc[x[i]=ss[i]];
        for (i=1;i<m;++i) cc[i]+=cc[i-1];
        for (i=n-1;i>=0;--i) sa[--cc[x[i]]]=i;
        for (k=1;k<=n;k<<=1)
        {
            p=0;
            for (i=n-k;i<n;++i) y[p++]=i;
            for (i=0;i<n;++i) if (sa[i]>=k) y[p++]=sa[i]-k;
            for (i=0;i<m;++i) cc[i]=0;
            for (i=0;i<n;++i) ++cc[x[y[i]]];
            for (i=1;i<m;++i) cc[i]+=cc[i-1];
            for (i=n-1;i>=0;--i) sa[--cc[x[y[i]]]]=y[i];
            swap(x,y);m=1;x[sa[0]]=0;
            for (i=1;i<n;++i) x[sa[i]]=cmp(y,sa[i],sa[i-1],k) ? m-1 : m++;
            if (m>=n) break;
        }
    }
    int main()
    {
        int i,n1;
        scanf("%s",&ss);n1=strlen(ss);
        for (i=0;i<n1-1;++i) ss[i+n1]=ss[i]; n=n1*2-1;
        for (i=0;i<n1;++i) m=max(m,(int)ss[i]);
        ++m;build();
        for (i=0;i<n;++i)
          if (sa[i]<n1) printf("%c",ss[sa[i]+n1-1]);
        printf("
    ");
    }
    View Code

    poj2406Power Strings

    题目大意:求给定字符串最多能被一个字符串重复几次得到。

    思路:虽然在学习后缀数组,不过第一反应是用kmp的思想,用失配数组进行操作。

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cstdio>
    #define maxnode 1000005
    using namespace std;
    char ss[maxnode];
    int f[maxnode]={0};
    int main()
    {
        int i,j,l;
        while(scanf("%s",&ss)==1)
        {
          l=strlen(ss);if (l==1&&ss[0]=='.') break;
          f[0]=f[1]=0;
          for (i=1;i<l;++i)
          {
            j=f[i];
            while(j&&ss[i]!=ss[j]) j=f[j];
            f[i+1]= ss[i]==ss[j] ? j+1 : 0;
          }
          if (f[l]>0&&l%(l-f[l])==0) printf("%d
    ",l/(l-f[l]));
          else printf("1
    ");
        }
    }
    View Code

    poj2774Long Long Message

    题目大意:求两个字符串的最长连续公共字串。

    思路:将两个字符串s1,s2连在一起,中间用一个特殊的符号连接(我用的是‘$’),求出满足起点在特殊符号两边、并且公共前缀最长的答案就可以了。求这个答案的时候,首先按height建立线段树,然后记录在以排名为下标的sa数组中,每一个串s1对应的后缀的前一个和后一个为串s2对应的后缀的排名,穷举每一个s1串的后缀,然后在线段树中查询之前记录下的min(前+1~rank(i))和min(rank(i)+1~后)中取较小值(这里还要和n-i取较小值),这里一定有最大的最小值在这一前一后之间取得。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxnode 200005
    #define inf 2100000000LL
    using namespace std;
    char s1[maxnode],s2[maxnode],ss[maxnode];
    int t1[maxnode]={0},t2[maxnode]={0},cc[maxnode]={0},n,m=0,sa[maxnode]={0},rank[maxnode]={0},height[maxnode]={0},tree[maxnode*4]={0},
        ml[maxnode]={0},mr[maxnode]={0};
    bool cmp(int *y,int a,int b,int k)
    {
        int a2,b2;
        a2= a+k>=n ? -1 : y[a+k];
        b2= b+k>=n ? -1 : y[b+k];
        a=y[a];b=y[b];
        return a==b&&a2==b2;
    }
    void buildt(int i,int l,int r)
    {
        int mid;
        if (l==r){tree[i]=height[l];return;}
        mid=(l+r)/2;buildt(i*2,l,mid);buildt(i*2+1,mid+1,r);
        tree[i]=min(tree[i*2],tree[i*2+1]);
    }
    int task(int i,int l,int r,int ll,int rr)
    {
        int mid,minn=inf;
        if (ll<=l&&r<=rr) return tree[i];  mid=(l+r)/2;
        if (ll<=mid) minn=min(minn,task(i*2,l,mid,ll,rr));
        if (rr>mid) minn=min(minn,task(i*2+1,mid+1,r,ll,rr));
        return minn;
    }
    void build()
    {
        int i,k,p;int *x=t1;int *y=t2;
        for (i=0;i<m;++i) cc[i]=0;
        for (i=0;i<n;++i) ++cc[x[i]=ss[i]];
        for (i=1;i<m;++i) cc[i]+=cc[i-1];
        for (i=n-1;i>=0;--i) sa[--cc[x[i]]]=i;
        for (k=1;k<=n;k<<=1)
        {
            p=0;
            for (i=n-k;i<n;++i) y[p++]=i;
            for (i=0;i<n;++i) if (sa[i]>=k) y[p++]=sa[i]-k;
            for (i=0;i<m;++i) cc[i]=0;
            for (i=0;i<n;++i) ++cc[x[y[i]]];
            for (i=1;i<m;++i) cc[i]+=cc[i-1];
            for (i=n-1;i>=0;--i) sa[--cc[x[y[i]]]]=y[i];
            swap(x,y);x[sa[0]]=0;m=1;
            for (i=1;i<n;++i) x[sa[i]]=cmp(y,sa[i],sa[i-1],k) ? m-1 : m++;
            if (m>=n) break;
        }
    }
    void pre()
    {
        int i,j,k=0;
        for (i=0;i<n;++i) rank[sa[i]]=i;
        for (i=0;i<n;++i)
        {
            if (!rank[i]) continue;
            if (k) --k; j=sa[rank[i]-1];
            while(ss[i+k]==ss[j+k]) ++k;
            height[rank[i]]=k;
        }
    }
    int main()
    {
        int i,j,n1,n2,ans=0;
        scanf("%s%s",&s1,&s2);n1=strlen(s1);n2=strlen(s2);n=n1+n2+1;
        for (i=0;i<n1;++i) ss[i]=s1[i]; ss[n1]='$';
        for (i=n1+1;i<n;++i) ss[i]=s2[i-n1-1];
        for (i=0;i<n;++i) m=max(m,(int)ss[i]);
        ++m;build();pre();buildt(1,0,n-1);
        j=-1;
        for (i=0;i<n;++i)
        {
            if (sa[i]>n1) j=i;
            else ml[sa[i]]=j;
        }
        j=-1;
        for (i=n-1;i>=0;--i)
        {
            if (sa[i]>n1) j=i;
            else mr[sa[i]]=j;
        }
        for (i=0;i<n1;++i)
        {
            if (n1-i<=ans) break;
            if (ml[i]!=-1) ans=max(ans,min(n1-i,task(1,0,n-1,ml[i]+1,rank[i])));
            if (mr[i]!=-1) ans=max(ans,min(n1-i,task(1,0,n-1,rank[i]+1,mr[i])));
        }
        printf("%d
    ",ans);
    }
    View Code

     其实完全没必要再这么麻烦,我们只要从头扫一遍height数组,找到满足要求的最大的值就可以了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxnode 200005
    #define inf 2100000000LL
    using namespace std;
    char s1[maxnode],s2[maxnode],ss[maxnode];
    int t1[maxnode]={0},t2[maxnode]={0},cc[maxnode]={0},n,m=0,sa[maxnode]={0},rank[maxnode]={0},height[maxnode]={0};
    bool cmp(int *y,int a,int b,int k)
    {
        int a2,b2;
        a2= a+k>=n ? -1 : y[a+k];
        b2= b+k>=n ? -1 : y[b+k];
        a=y[a];b=y[b];
        return a==b&&a2==b2;
    }
    void build()
    {
        int i,k,p;int *x=t1;int *y=t2;
        for (i=0;i<m;++i) cc[i]=0;
        for (i=0;i<n;++i) ++cc[x[i]=ss[i]];
        for (i=1;i<m;++i) cc[i]+=cc[i-1];
        for (i=n-1;i>=0;--i) sa[--cc[x[i]]]=i;
        for (k=1;k<=n;k<<=1)
        {
            p=0;
            for (i=n-k;i<n;++i) y[p++]=i;
            for (i=0;i<n;++i) if (sa[i]>=k) y[p++]=sa[i]-k;
            for (i=0;i<m;++i) cc[i]=0;
            for (i=0;i<n;++i) ++cc[x[y[i]]];
            for (i=1;i<m;++i) cc[i]+=cc[i-1];
            for (i=n-1;i>=0;--i) sa[--cc[x[y[i]]]]=y[i];
            swap(x,y);x[sa[0]]=0;m=1;
            for (i=1;i<n;++i) x[sa[i]]=cmp(y,sa[i],sa[i-1],k) ? m-1 : m++;
            if (m>=n) break;
        }
    }
    void pre()
    {
        int i,j,k=0;
        for (i=0;i<n;++i) rank[sa[i]]=i;
        for (i=0;i<n;++i)
        {
            if (!rank[i]) continue;
            if (k) --k; j=sa[rank[i]-1];
            while(ss[i+k]==ss[j+k]) ++k;
            height[rank[i]]=k;
        }
    }
    int main()
    {
        int i,j,n1,n2,ans=0;
        scanf("%s%s",&s1,&s2);n1=strlen(s1);n2=strlen(s2);n=n1+n2+1;
        for (i=0;i<n1;++i) ss[i]=s1[i]; ss[n1]='$';
        for (i=n1+1;i<n;++i) ss[i]=s2[i-n1-1];
        for (i=0;i<n;++i) m=max(m,(int)ss[i]);
        ++m;build();pre();
        for (i=1;i<n;++i)
          if ((sa[i-1]<n1&&sa[i]>n1)||(sa[i-1]>n1&&sa[i]<n1)) ans=max(ans,height[i]);
        printf("%d
    ",ans);
    }
    View Code

    bzoj3238差异

    题目大意:求sigma(lenTi+lenTj-2*lcp(Ti,Tj)),1<=i<j<=n,Ti表示从第i个字符开始的后缀,小标从1开始。

    思路:将sigma拆开,可以发现主要就是求2*lcp(Ti,Tj),先用后缀数组构建height,然后建立线段树,保存最小值和最小值的位置,分治处理,对区间[l,r],找线段树中[l+1,r](下表一定注意,因为height[i]表示i和i-1的lcp长度)的最小值minn和位置minp,给ans减去(minn*(minp-l)*(r-minp+1))(还是要十分注意下标),然后在把sigma中其他部分加起来就行了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxnode 500005
    #define inf 2100000000LL
    #define LL long long
    using namespace std;
    struct use{
        int minn,minp;
    }tree[maxnode*4]={0};
    char ss[maxnode]={0};
    int t1[maxnode]={0},t2[maxnode]={0},cc[maxnode]={0},sa[maxnode]={0},rank[maxnode]={0},height[maxnode]={0},n,m=0;
    long long ans=0;
    bool cmp(int *y,int a,int b,int k)
    {
        int a2,b2;
        a2= a+k>=n ? -1 : y[a+k];
        b2= b+k>=n ? -1 : y[b+k];
        a=y[a];b=y[b];
        return a==b&&a2==b2;
    }
    void build()
    {
        int i,k,p; int *x=t1;int *y=t2;
        for (i=0;i<m;++i) cc[i]=0;
        for (i=0;i<n;++i) ++cc[x[i]=ss[i]];
        for (i=1;i<m;++i) cc[i]+=cc[i-1];
        for (i=n-1;i>=0;--i) sa[--cc[x[i]]]=i;
        for (k=1;k<=n;k<<=1)
        {
            p=0;
            for (i=n-k;i<n;++i) y[p++]=i;
            for (i=0;i<n;++i) if (sa[i]>=k) y[p++]=sa[i]-k;
            for (i=0;i<m;++i) cc[i]=0;
            for (i=0;i<n;++i) ++cc[x[y[i]]];
            for (i=1;i<m;++i) cc[i]+=cc[i-1];
            for (i=n-1;i>=0;--i) sa[--cc[x[y[i]]]]=y[i];
            swap(x,y);m=1;x[sa[0]]=0;
            for (i=1;i<n;++i) x[sa[i]]=cmp(y,sa[i],sa[i-1],k) ? m-1 : m++;
            if (m>=n) break;
        }
    }
    void pre()
    {
        int i,j,k=0;
        for (i=0;i<n;++i) rank[sa[i]]=i;
        for (i=0;i<n;++i)
        {
            if (!rank[i]) continue;
            if (k) --k; j=sa[rank[i]-1];
            while(ss[i+k]==ss[j+k]) ++k;
            height[rank[i]]=k;
        }
    }
    use updata(use x,use y){return x.minn<=y.minn ? x : y;}
    void buildt(int i,int l,int r)
    {
        int mid;
        if (l==r){tree[i].minn=height[l];tree[i].minp=l;return;};
        mid=(l+r)/2;
        buildt(i*2,l,mid);buildt(i*2+1,mid+1,r);
        tree[i]=updata(tree[i*2],tree[i*2+1]);
    }
    use task(int i,int l,int r,int ll,int rr)
    {
        use x1,x2; int mid;
        if (ll<=l&&r<=rr) return tree[i];
        mid=(l+r)/2;x1.minn=x2.minn=inf;
        if (ll<=mid) x1=task(i*2,l,mid,ll,rr);
        if (rr>mid) x2=task(i*2+1,mid+1,r,ll,rr);
        return updata(x1,x2);
    }
    void work(int l,int r)
    {
        use xx;
        if (l>=r) return;
        xx=task(1,1,n-1,l+1,r);
        work(l,xx.minp-1);work(xx.minp,r);
        ans-=2*(LL)xx.minn*(LL)(xx.minp-l)*(LL)(r-xx.minp+1);
    }
    int main()
    {
        int i,j;
        scanf("%s",&ss);n=strlen(ss);
        for (i=0;i<n;++i) m=max(m,(int)ss[i]);
        ++m;build();pre();buildt(1,1,n-1);
        for (i=0;i<n;++i) ans+=(LL)(n-1)*(LL)(n-i);
        work(0,n-1);printf("%lld
    ",ans);
    }
    View Code

    bzoj2251 外星联络

    题目大意:求出一个01串中出现次数多于一次的字串的个数(按字典序排序)。

    思路:用后缀数组做出height后,所有后缀都排好序了,那么靠前面并且长度小的就是字典序小的。但是这里要保证不重复并且超过两次出现,所以我们每次从这一位的height[i]+1的长度到这个后缀长度开始往后找,只要height[j]>height[i]+1就一直往后,这样保证了开头是单调递增的长度也单调,所以答案就是字典序排好的了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxnode 3005
    using namespace std;
    int sa[maxnode],t1[maxnode],t2[maxnode],c[maxnode],n,m,height[maxnode]={0},rank[maxnode]={0};
    char s[maxnode];
    bool cmp(int *y,int a,int b,int k)
    {
        int a2,b2;
        a2= a+k>=n ? -1 : y[a+k];
        b2= b+k>=n ? -1 : y[b+k];
        a=y[a];b=y[b];
        return a==b&&a2==b2;
    }
    void build()
    {
        int *x=t1,*y=t2,i,k,p;
        for (i=0;i<=m;++i) c[i]=0;
        for (i=0;i<n;++i) ++c[x[i]=(s[i]-'0')];
        for (i=1;i<=m;++i) c[i]+=c[i-1];
        for (i=n-1;i>=0;--i) sa[--c[x[i]]]=i;
        for (k=1;k<=n;k<<=1)
        {
            p=0;
            for (i=n-k;i<n;++i) y[p++]=i;
            for (i=0;i<n;++i) if (sa[i]>=k) y[p++]=sa[i]-k;
            for (i=0;i<=m;++i) c[i]=0;
            for (i=0;i<n;++i) ++c[x[y[i]]];
            for (i=1;i<=m;++i) c[i]+=c[i-1];
            for (i=n-1;i>=0;--i) sa[--c[x[y[i]]]]=y[i];
            swap(x,y);m=1;x[sa[0]]=0;
            for (i=1;i<n;++i) x[sa[i]]= cmp(y,sa[i],sa[i-1],k) ? m-1 : m++;
            if (m>=n) break;
        }
    }
    void pre()
    {
        int k=0,i,j;
        for (i=0;i<n;++i) rank[sa[i]]=i;
        for (i=0;i<n;++i)
        {
            if (!rank[i]) continue;
            if (k) --k;j=sa[rank[i]-1];
            while(s[i+k]==s[j+k]) ++k;
            height[rank[i]]=k;
        }
    }
    int main()
    {
        int i,j,k;
        scanf("%d",&n);m=1;
        for (i=0;i<n;++i)
        {
            while(scanf("%c",&s[i])==1)
              if (s[i]>='0'&&s[i]<='1') break;
        }
        build();pre();
        for (i=0;i<n;++i)
        {
            for (j=height[i]+1;j+sa[i]<=n;++j)
            {
                for (k=i+1;k<n&&height[k]>=j;++k);
                if (k-i>1) printf("%d
    ",k-i);
            }
        }
    }
    View Code

    bzoj3879 SvT

    题目大意:给定一个字符串,多组询问,每次问某些后缀两两之间lcp的长度和。

    思路:对字符串建后缀数组,对于每组询问,按rank排序后,求出相邻两个的lcp,对这个排序之后,类似差异的做法,用这个最小值更新lcp也是这个的答案。

    注意:st表预处理的时候,i后面2^j个的时候,要判断i+2^j是否小于n,否则会re。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 500005
    #define M 3000005
    #define up 20
    #define inf 2100000000
    #define LL long long
    #define p 23333333333333333LL
    using namespace std;
    char s[N];
    struct tree{
        int mx,mn,del;
        void init(){mx=-inf;mn=inf;del=1;}
    }tr[N<<2];
    struct use{
        int mn,po;
        bool operator<(const use&x)const{return mn<x.mn;}
    }ai[M];
    int x1[N],x2[N],n,m,sa[N],rank[N],height[N]={0},ci[N],cc[N],lo[N],mn[N][up];
    int cmp(int *y,int a,int b,int k){
        int aa,bb;
        aa=(a+k>=n ? -1 : y[a+k]);
        bb=(b+k>=n ? -1 : y[b+k]);
        a=y[a];b=y[b];
        return a==b&&aa==bb;}
    int mcm(int x,int y){return rank[x]<rank[y];}
    void getsa(){
        int i,k,pp;int *x=x1;int *y=x2;
        for (i=0;i<m;++i) cc[i]=0;
        for (i=0;i<n;++i) ++cc[x[i]=s[i]-'a'];
        for (i=1;i<m;++i) cc[i]+=cc[i-1];
        for (i=n-1;i>=0;--i) sa[--cc[x[i]]]=i;
        for (k=1;k<=n;k<<=1){
            for (pp=0,i=n-k;i<n;++i) y[pp++]=i;
            for (i=0;i<n;++i) if (sa[i]>=k) y[pp++]=sa[i]-k;
            for (i=0;i<m;++i) cc[i]=0;
            for (i=0;i<n;++i) ++cc[x[y[i]]];
            for (i=1;i<m;++i) cc[i]+=cc[i-1];
            for (i=n-1;i>=0;--i) sa[--cc[x[y[i]]]]=y[i];
            swap(x,y);m=1;x[sa[0]]=0;
            for (i=1;i<n;++i) x[sa[i]]=(cmp(y,sa[i],sa[i-1],k) ? m-1 : m++);
            if (m>=n) break;
        }
    }
    void pre(){
        int i,j,k=0;
        for (i=0;i<n;++i) rank[sa[i]]=i;
        for (i=0;i<n;++i){
            if (!rank[i]) continue;
            if (k) --k; j=sa[rank[i]-1];
            while(s[j+k]==s[i+k]) ++k;
            height[rank[i]]=k;
        }memset(mn,127/3,sizeof(mn));
        for (i=0;i<n;++i) mn[i][0]=height[i];
        for (i=1;(1<<i)<=n;++i){
            for (j=0;j+(1<<(i-1))<n;++j)
                mn[j][i]=min(mn[j][i-1],mn[j+(1<<(i-1))][i-1]);
        }
        for (k=0,i=1;i<=n;++i){
            if ((1<<(k+1))<=i) ++k;
            lo[i]=k;
        }
    }
    void pushdown(int i){
        tr[i<<1].mx=tr[i<<1|1].mx=-inf;
        tr[i<<1].mn=tr[i<<1|1].mn=inf;
        tr[i<<1].del^=1;tr[i<<1|1].del^=1;
        tr[i].del=0;}
    tree updata(tree x,tree y){
        tree c;c.del=0;
        c.mx=max(x.mx,y.mx);
        c.mn=min(x.mn,y.mn);
        return c;}
    void ins(int i,int l,int r,int x){
        if (l==r){tr[i]=(tree){l,l,0};return;}
        int mid=(l+r)>>1;
        if (tr[i].del) pushdown(i);
        if (x<=mid) ins(i<<1,l,mid,x);
        else ins(i<<1|1,mid+1,r,x);
        tr[i]=updata(tr[i<<1],tr[i<<1|1]);}
    int amx(int i,int l,int r,int ll,int rr){
        if (ll<=l&&r<=rr) return tr[i].mx;
        int mid=(l+r)>>1;int mm=-inf;
        if (tr[i].del) pushdown(i);
        if (ll<=mid) mm=max(mm,amx(i<<1,l,mid,ll,rr));
        if (rr>mid) mm=max(mm,amx(i<<1|1,mid+1,r,ll,rr));
        return mm;}
    int amn(int i,int l,int r,int ll,int rr){
        if (ll<=l&&r<=rr) return tr[i].mn;
        int mid=(l+r)>>1;int mm=inf;
        if (tr[i].del) pushdown(i);
        if (ll<=mid) mm=min(mm,amn(i<<1,l,mid,ll,rr));
        if (rr>mid) mm=min(mm,amn(i<<1|1,mid+1,r,ll,rr));
        return mm;}
    int getmn(int l,int r){
        int x=lo[r-l];++l;
        return min(mn[l][x],mn[r-(1<<x)+1][x]);}
    int main(){
        int i,j,q,t,l,r;LL ans;scanf("%d%d",&n,&q);
        scanf("%s",s);m=26;
        getsa();pre();
        while(q--){
            scanf("%d",&t);
            for (i=1;i<=t;++i){scanf("%d",&ci[i]);--ci[i];}
            sort(ci+1,ci+t+1,mcm);t=unique(ci+1,ci+t+1)-ci-1;
            for (i=2;i<=t;++i)
                ai[i]=(use){getmn(rank[ci[i-1]],rank[ci[i]]),i};
            sort(ai+2,ai+t+1);ans=0LL;
            tr[1].init();
            ins(1,1,t+1,1);ins(1,1,t+1,t+1);
            for (i=2;i<=t;++i){
                j=ai[i].po;
                l=amx(1,1,t+1,1,j-1);
                r=amn(1,1,t+1,j+1,t+1);
                ans=(ans+(LL)ai[i].mn*(LL)(j-l)*(LL)(r-j)%p)%p;
                ins(1,1,t+1,j);
            }printf("%I64d
    ",ans);
        }
    }
    View Code

    bzoj4453 cys就是要拿英魂!(!!!

    题目大意:给定一个字符串,每次询问一个区间内的最大子串。

    思路:这个子串肯定是这个区间的一个后缀,所以考虑求一个区间最大后缀。如果按照左端点从大到小扫的话,每个点处取得最大值的位置是单调不减的,所以可以用一个栈维护这样的决策序列,先弹掉整个区间都不优的,之后从那个可能优的区间里二分,就是这个点能影响到的范围,比较两个后缀大小就是比较lcp之后的那个字母(如果后缀的lcp超过短串的长度,就是长串更长),所以可以用后缀数组预处理。

    注意:后缀数组求lcp时下标是rank。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 100005
    #define up 20
    #define inf 2100000000
    using namespace std;
    struct use{
        int x,l,r;
        bool operator<(const use&x)const{return l>x.l;}
    }ai[N],zh[N];
    char ss[N];
    int zt=0,lo[N],st[N][up],sa[N],height[N],rank[N],x1[N],x2[N],cc[N],tr[N<<2],del[N<<2];
    int in(){
        char ch=getchar();int x=0;
        while(ch<'0'||ch>'9') ch=getchar();
        while(ch>='0'&&ch<='9'){
            x=x*10+ch-'0';ch=getchar();
        }return x;}
    int cmp(int n,int *y,int a,int b,int k){
        int aa,bb;
        aa=(a+k>=n ? -1 : y[a+k]);
        bb=(b+k>=n ? -1 : y[b+k]);
        a=y[a];b=y[b];
        return (a==b&&aa==bb);}
    void pre(int n,int m){
        int i,j,k,p;int *x=x1;int *y=x2;
        for (i=0;i<m;++i) cc[i]=0;
        for (i=0;i<n;++i) ++cc[x[i]=ss[i]];
        for (i=1;i<m;++i) cc[i]+=cc[i-1];
        for (i=n-1;i>=0;--i) sa[--cc[x[i]]]=i;
        for (k=1;k<=n;k<<=1){
            for (p=0,i=n-k;i<n;++i) y[p++]=i;
            for (i=0;i<n;++i) if (sa[i]>=k) y[p++]=sa[i]-k;
            for (i=0;i<m;++i) cc[i]=0;
            for (i=0;i<n;++i) ++cc[x[y[i]]];
            for (i=1;i<m;++i) cc[i]+=cc[i-1];
            for (i=n-1;i>=0;--i) sa[--cc[x[y[i]]]]=y[i];
            swap(x,y);m=1;x[sa[0]]=0;
            for (i=1;i<n;++i) x[sa[i]]=(cmp(n,y,sa[i],sa[i-1],k) ? m-1 : m++);
            if (m>=n) break;
        }for (i=0;i<n;++i) rank[sa[i]]=i;
        height[rank[0]]=k=0;
        for (i=0;i<n;++i){
            if (!rank[i]) continue;
            if (k) --k; j=sa[rank[i]-1];
            while(ss[i+k]==ss[j+k]) ++k;
            height[rank[i]]=k;
        }for (i=0;i<n;++i) st[i][0]=height[i];
        for (j=1;(1<<j)<=n;++j)
            for (i=0;i+(1<<(j-1))<n;++i)
                st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
        for (j=0,i=1;i<=n;++i){
            if ((1<<(j+1))<=i) ++j;
            lo[i]=j;
        }
    }
    int lcp(int l,int r){
        l=rank[l];r=rank[r];
        if (l>r) swap(l,r);
        int d=lo[r-l];++l;
        return min(st[l][d],st[r-(1<<d)+1][d]);}
    bool mcm(int x,int y,int r){
        int lc=lcp(x,y);
        if (y+lc>r) return true;
        return ss[x+lc]>ss[y+lc];}
    void pushdown(int i){
        del[i<<1]=del[i<<1|1]=del[i];
        tr[i<<1]=tr[i<<1|1]=del[i];
        del[i]=-1;}
    void tch(int i,int l,int r,int ll,int rr,int x){
        if (ll<=l&&r<=rr){tr[i]=del[i]=x;return;}
        int mid=(l+r)>>1;
        if (del[i]>=0) pushdown(i);
        if (ll<=mid) tch(i<<1,l,mid,ll,rr,x);
        if (rr>mid) tch(i<<1|1,mid+1,r,ll,rr,x);}
    int geta(int i,int l,int r,int x){
        if (l==r) return tr[i];
        int mid=(l+r)>>1;
        if (del[i]>=0) pushdown(i);
        if (x<=mid) return geta(i<<1,l,mid,x);
        else return geta(i<<1|1,mid+1,r,x);}
    int gete(int x,use y){
        int l,r,mid,ans=y.l-1;
        l=y.l;r=y.r;
        while(l<=r){
            mid=(l+r)>>1;
            if (mcm(x,y.x,mid)){l=mid+1;ans=mid;}
            else r=mid-1;
        }return ans;}
    void getz(int l,int x){
        while(zt){
            if (mcm(x,zh[zt].x,zh[zt].r)) --zt;
            else break;
        }if (!zt){
            zh[++zt]=(use){x,x,zh[0].r-1};
            tch(1,0,l-1,x,l-1,x);
        }else{
            int r=gete(x,zh[zt]);
            zh[zt].l=r+1;
            zh[++zt]=(use){x,x,r};
            tch(1,0,l-1,x,r,x);
        }
    }
    int main(){
        int i,j,l,n,m=0;
        scanf("%s",ss);l=strlen(ss);
        for (i=0;i<l;++i) m=max(m,ss[i]+1);
        for (pre(l,m),n=in(),i=1;i<=n;++i)
            ai[i]=(use){i,in()-1,in()-1};
        sort(ai+1,ai+n+1);
        zh[0]=(use){0,0,l};
        memset(del,-60,sizeof(del));
        for (j=1,i=l-1;i>=0;--i){
            getz(l,i);
            for (;j<=n&&ai[j].l==i;++j)
                x1[ai[j].x]=geta(1,0,l-1,ai[j].r);
        }for (i=1;i<=n;++i) printf("%d
    ",x1[i]+1);
    }
    View Code

    bzoj4556 字符串

    题目大意:给定一个字符串s,m组询问:s[a...b]的子串和s[c...d]的最长公共前缀。

    思路:用后缀数组求出height之后,二分答案,每次找height满足要求的区间内找有没有在[a,b-mid+1]范围内的,用主席树(第一层是rank,第二层是位置)查询。

    注意:1)不要读错题;

         2)如果找rank的前驱后继,可能会出现公共前缀很长,但是被b这个位置截掉的情况。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 100005
    #define up 20
    #define M 2000005
    using namespace std;
    int in(){
        char ch=getchar();int x=0;
        while(ch<'0'||ch>'9') ch=getchar();
        while(ch>='0'&&ch<='9'){
            x=x*10+ch-'0';ch=getchar();
        }return x;}
    struct use{int l,r,sm;}tr[M];
    int n,m,sa[N],rank[N],height[N],ci[N],x1[N],x2[N],lo[N],di[up][N],rt[N]={0},tt=0;
    char ss[N];
    bool cmp(int *y,int a,int b,int k){
        int aa,bb;
        aa=(a+k>=n ? -1 : y[a+k]);
        bb=(b+k>=n ? -1 : y[b+k]);
        a=y[a];b=y[b];
        return a==b&&aa==bb;}
    void pre(){
        int i,j,k,p;m=26;int *x=x1;int *y=x2;
        for (i=0;i<m;++i) ci[i]=0;
        for (i=0;i<n;++i) ++ci[x[i]=(ss[i]-'a')];
        for (i=1;i<m;++i) ci[i]+=ci[i-1];
        for (i=n-1;i>=0;--i) sa[--ci[x[i]]]=i;
        for (k=1;k<=n;k<<=1){
            for (p=0,i=n-k;i<n;++i) y[p++]=i;
            for (i=0;i<n;++i) if (sa[i]>=k) y[p++]=sa[i]-k;
            for (i=0;i<m;++i) ci[i]=0;
            for (i=0;i<n;++i) ++ci[x[y[i]]];
            for (i=1;i<m;++i) ci[i]+=ci[i-1];
            for (i=n-1;i>=0;--i) sa[--ci[x[y[i]]]]=y[i];
            swap(x,y);m=1;x[sa[0]]=0;
            for (i=1;i<n;++i) x[sa[i]]=(cmp(y,sa[i],sa[i-1],k) ? m-1 : m++);
            if (m>=n) break;
        }for (i=0;i<n;++i) rank[sa[i]]=i;
        for (k=i=0;i<n;++i){
            if (!rank[i]) continue;
            if (k) --k;j=sa[rank[i]-1];
            while(ss[i+k]==ss[j+k]) ++k;
            height[rank[i]]=k;
        }for (i=0;i<n;++i) di[0][i]=height[i];
        for (i=1;(1<<i)<=n;++i)
            for (j=0;j+(1<<(i-1))<n;++j)
                di[i][j]=min(di[i-1][j],di[i-1][j+(1<<(i-1))]);
        for (k=0,i=1;i<=n;++i){
            if ((1<<(k+1))<=i) ++k;
            lo[i]=k;
        }
    }
    int amn(int x,int y){
        if (x==y) return (n-sa[x]);
        if (x>y) swap(x,y);
        int k=lo[y-x];++x;
        return min(di[k][x],di[k][y-(1<<k)+1]);
    }
    void ins(int &i,int la,int l,int r,int x){
        tr[i=++tt]=tr[la];++tr[i].sm;
        if (l==r) return;
        int mid=(l+r)>>1;
        if (x<=mid) ins(tr[i].l,tr[la].l,l,mid,x);
        else ins(tr[i].r,tr[la].r,mid+1,r,x);
    }
    int ask(int i,int j,int l,int r,int ll,int rr){
        if (!(tr[j].sm-tr[i].sm)) return 0;
        if (ll<=l&&r<=rr) return tr[j].sm-tr[i].sm;
        int sm=0,mid=(l+r)>>1;
        if (ll<=mid) sm+=ask(tr[i].l,tr[j].l,l,mid,ll,rr);
        if (rr>mid) sm+=ask(tr[i].r,tr[j].r,mid+1,r,ll,rr);
        return sm;}
    int getl(int c,int x){
        int l,r,mid,ans;
        l=1;r=rank[c-1];ans=r+1;
        while(l<=r){
            mid=(l+r)>>1;
            if (amn(mid-1,rank[c-1])>=x){r=mid-1;ans=mid;}
            else l=mid+1;
        }return ans-1;
    }
    int getr(int c,int x){
        int l,r,mid,ans;
        l=rank[c-1]+1;r=n-1;ans=l-1;
        while(l<=r){
            mid=(l+r)>>1;
            if (amn(rank[c-1],mid)>=x){l=mid+1;ans=mid;}
            else r=mid-1;
        }return ans;
    }
    int query(int a,int b,int c,int d){
        int l,r,le,re,mid,mx=0;
        l=0;r=min(d-c+1,b-a+1);
        while(l<=r){
            mid=(l+r)>>1;
            le=getl(c,mid);
            re=getr(c,mid);
            if (ask(rt[le],rt[re+1],1,n,a,b-mid+1)){l=mid+1;mx=mid;}
            else r=mid-1;
        }return mx;
    }
    int main(){
        int q,i,a,b,c,d;
        n=in();q=in();
        scanf("%s",ss);pre();
        for (i=1;i<=n;++i)
            ins(rt[i],rt[i-1],1,n,sa[i-1]+1);
        for (i=1;i<=q;++i){
            a=in();b=in();c=in();d=in();
            printf("%d
    ",query(a,b,c,d));
        }
    }
    View Code

    bzoj2119 股市的预测(!!!

    题目大意:求隔过长度为m-1的段后两边(不一定是全部)的升降幅度一样的子串个数。

    思路:差分之后就是求ABA的形式,其中B的长度为m的个数。枚举A的长度i,每i个点的位置为j,j和i+m+j比较一下求出向前向后最多能扩展的长度x,如果长度>=i就可以累加答案x-i+1,注意这里x是在这个j的范围内,不能超过j-i+1和j+i,否则会重复统计。

    orz vaorz vaorz va

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 100005
    #define up 17
    #define LL long long
    using namespace std;
    int in(){
        char ch=getchar();int x=0,f=1;
        while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
        if (ch=='-'){f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){
            x=x*10+ch-'0';ch=getchar();
        }return x*f;}
    int cz=0,ai[N],x1[N],x2[N],sa[N],rank[N],height[N]={0},cc[N],st[up][N],lo[N];
    LL ci[N];
    int cmp(int n,int *y,int a,int b,int k){
        int aa,bb;
        aa=(a+k>=n ? -1 : y[a+k]);
        bb=(b+k>=n ? -1 : y[b+k]);
        a=y[a];b=y[b];
        return a==b&&aa==bb;}
    void pre(int n,int m){
        int i,j,p,k;int *x=x1;int *y=x2;
        for (i=0;i<m;++i) cc[i]=0;
        for (i=0;i<n;++i) ++cc[x[i]=ai[i]];
        for (i=1;i<m;++i) cc[i]+=cc[i-1];
        for (i=n-1;i>=0;--i) sa[--cc[x[i]]]=i;
        for (k=1;k<=n;k<<=1){
            for (p=0,i=n-k;i<n;++i) y[p++]=i;
            for (i=0;i<n;++i) if (sa[i]>=k) y[p++]=sa[i]-k;
            for (i=0;i<m;++i) cc[i]=0;
            for (i=0;i<n;++i) ++cc[x[y[i]]];
            for (i=1;i<m;++i) cc[i]+=cc[i-1];
            for (i=n-1;i>=0;--i) sa[--cc[x[y[i]]]]=y[i];
            swap(x,y);m=1;x[sa[0]]=0;
            for (i=1;i<n;++i) x[sa[i]]=(cmp(n,y,sa[i],sa[i-1],k) ? m-1 : m++);
            if (m>=n) break;
        }for (i=0;i<n;++i) rank[sa[i]]=i;
        for (k=i=0;i<n;++i){
            if (!rank[i]) continue;
            if (k) --k;j=sa[rank[i]-1];
            for (;ai[i+k]==ai[j+k];++k);
            height[rank[i]]=k;
        }for (i=0;i<n;++i) st[0][i]=height[i];
        for (i=1;(1<<i)<=n;++i)
            for (j=0;j+(1<<(i-1))<n;++j)
                st[i][j]=min(st[i-1][j],st[i-1][j+(1<<(i-1))]);
        for (k=0,i=1;i<=n;++i){
            if ((1<<(k+1))<=i) ++k;
            lo[i]=k;
        }
    }
    int amn(int x,int y){
        if (x>y) swap(x,y);
        int k=lo[y-x];++x;
        return min(st[k][x],st[k][y-(1<<k)+1]);
    }
    int main(){
        int i,j,a,b,n,m;LL ans=0LL;n=in();m=in();
        for (i=1;i<=n;++i){
            ai[i]=in();
            if (i>1) ci[++cz]=(LL)ai[i]-ai[i-1];
        }sort(ci+1,ci+cz+1);
        cz=unique(ci+1,ci+cz+1)-ci-1;
        for (--n,i=1;i<=n;++i) ai[i-1]=upper_bound(ci+1,ci+cz+1,(LL)ai[i+1]-ai[i])-ci-2;
        ai[n]=cz;++cz;
        for (i=1;i<=n;++i) ai[n*2+1-i]=ai[i-1];
        pre(n*2+1,cz);
        for (i=1;i+i+m<=n;++i)
            for (a=0,j=0;j+i+m<n;j+=i){
                b=min(i,amn(rank[j],rank[j+i+m]));
                if (a+b>=i) ans+=(LL)(a+b-i+1);
                a=min(i-1,amn(rank[n*2-(i+j-1)],rank[n*2-(i+i+j+m-1)]));
            }
        printf("%I64d
    ",ans);
    }
    View Code

    bzoj4566 找相同字符

    题目大意:求a和b串的公共子串个数(位置不同的算不同的)。

    思路:中间加一个不再字符集的字母接起来。和差异一样,只是统计答案的时候是左右边分别属于a、b的个数的乘积。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 400005
    #define LL long long
    using namespace std;
    struct use{int mn,po;}tr[N<<2],ci;
    int n=0,n1,sa[N],rank[N],height[N],x1[N],x2[N],cc[N],seg[N<<2];
    LL ans=0LL;
    char ss[N];
    void in(){
        char ch=getchar();
        while(ch<'a'||ch>'z') ch=getchar();
        while(ch>='a'&&ch<='z'){
            ss[n++]=ch;ch=getchar();
        }
    }
    int cmp(int *y,int a,int b,int k){
        int aa,bb;
        aa=(a+k>=n ? -1 : y[a+k]);
        bb=(b+k>=n ? -1 : y[b+k]);
        a=y[a];b=y[b];
        return (a==b&&aa==bb);
    }
    void pre(){
        int i,j,k,p,m;int *x=x1;int *y=x2;
        for (m=27,i=0;i<m;++i) cc[i]=0;
        for (i=0;i<n;++i) ++cc[x[i]=ss[i]-'a'];
        for (i=1;i<m;++i) cc[i]+=cc[i-1];
        for (i=n-1;i>=0;--i) sa[--cc[x[i]]]=i;
        for (k=1;k<=n;k<<=1){
            for (p=0,i=n-k;i<n;++i) y[p++]=i;
            for (i=0;i<n;++i) if (sa[i]>=k) y[p++]=sa[i]-k;
            for (i=0;i<m;++i) cc[i]=0;
            for (i=0;i<n;++i) ++cc[x[y[i]]];
            for (i=1;i<m;++i) cc[i]+=cc[i-1];
            for (i=n-1;i>=0;--i) sa[--cc[x[y[i]]]]=y[i];
            swap(x,y);m=1;x[sa[0]]=0;
            for (i=1;i<n;++i) x[sa[i]]=(cmp(y,sa[i],sa[i-1],k) ? m-1 : m++);
            if (m>=n) break;
        }for (i=0;i<n;++i) rank[sa[i]]=i;
        for (k=0,i=0;i<n;++i){
            if (!rank[i]) continue;
            if (k) --k;j=sa[rank[i]-1];
            for (;ss[i+k]==ss[j+k];++k);
            height[rank[i]]=k;
        }
    }
    use updata(use x,use y){
        use c;
        if (x.mn<=y.mn) c=x;
        else c=y;
        return c;}
    void build(int i,int l,int r){
        if (l==r){tr[i]=(use){height[l],l};return;}
        int mid=(l+r)>>1;
        build(i<<1,l,mid);build(i<<1|1,mid+1,r);
        tr[i]=updata(tr[i<<1],tr[i<<1|1]);
    }
    void buils(int i,int l,int r){
        if (l==r){seg[i]=(sa[l]<n1);return;}
        int mid=(l+r)>>1;
        buils(i<<1,l,mid);buils(i<<1|1,mid+1,r);
        seg[i]=seg[i<<1]+seg[i<<1|1];
    }
    void amn(int i,int l,int r,int ll,int rr){
        if (ll<=l&&r<=rr){
            if (l==ll) ci=tr[i];
            else ci=updata(ci,tr[i]);
            return;
        }int mid=(l+r)>>1;
        if (ll<=mid) amn(i<<1,l,mid,ll,rr);
        if (rr>mid) amn(i<<1|1,mid+1,r,ll,rr);
    }
    int ask(int i,int l,int r,int ll,int rr){
        if (ll<=l&&r<=rr) return seg[i];
        int sm=0,mid=(l+r)>>1;
        if (ll<=mid) sm+=ask(i<<1,l,mid,ll,rr);
        if (rr>mid) sm+=ask(i<<1|1,mid+1,r,ll,rr);
        return sm;
    }
    void work(int l,int r){
        if (l>=r) return;
        amn(1,1,n-1,l+1,r);
        int s1,s2;
        s1=ask(1,0,n-1,l,ci.po-1);
        s2=ask(1,0,n-1,ci.po,r);
        ans+=(LL)ci.mn*((LL)s1*(LL)(r-ci.po+1-s2)+(LL)(ci.po-l-s1)*(LL)s2);
        s1=ci.po;work(l,s1-1);work(s1,r);
    }
    int main(){
        in();n1=n;ss[n++]='z'+1;
        in();pre();
        build(1,1,n-1);buils(1,0,n-1);
        work(0,n-1);
        printf("%I64d
    ",ans);
    }
    View Code

    后缀平衡树

    bzoj2555

    题目大意:维护一个字符串,支持:(1)在末尾加一段字符;(2)查询一个字符串出现的次数。

    思路:维护前缀,用平衡树动态加入,比较的时候可以用二分+hash求出lcp,然后比较大小。查询x的次数的时候相当于<xS - <x的(S是一个比字符集大的字符)。

    注意:卡常技巧:(1)用unsigned int比unsigned long long快;(2)二分时定一个参数,如果参数长度的不同就把上界设为参数(参数取得25)。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 3000005
    #define p 569LL
    #define up 26
    #define UL unsigned int
    #define ji 25
    using namespace std;
    UL ha[N],mi[N],ha1[N];
    int le=0,l1,qt=0;
    char ss[N],s1[N];
    inline UL geth(int k,int l,int r){
        if (k) return (ha1[r]-(l-1>=0 ? ha1[l-1] : 0LL))*mi[N-r-1];
        else return (ha[r]-(l-1>=0 ? ha[l-1] : 0LL))*mi[N-r-1];}
    struct node{
        node *ch[2];
        int po,r,sz;
        int cmp(int k){
            char *s=(k ? s1 : ss);
            int l,r,mid,lc,len=(k ? l1 : le);
            lc=l=0;
            if (min(po,len)<=ji||(geth(0,po-ji,po-1)==geth(k,len-ji,len-1))) r=min(po,len);
            else r=ji;
            while(l<=r){
                mid=(l+r)>>1;
                if (geth(0,po-mid,po-1)==geth(k,len-mid,len-1)){lc=mid;l=mid+1;}
                else r=mid-1;
            }if (po==len&&lc==len) return -1;
            if (lc==po) return 1;
            if (lc==len) return 0;
            return (ss[po-lc-1]<s[len-lc-1]);
        }
        inline void updata(){
            sz=1;
            if (ch[0]!=NULL) sz+=ch[0]->sz;
            if (ch[1]!=NULL) sz+=ch[1]->sz;
        }
    }*rt,que[N*3];
    inline void in(){
        l1=0;char ch=getchar();
        while(ch<'A'||ch>'Z') ch=getchar();
        while(ch>='A'&&ch<='Z'){
            s1[l1++]=ch;ch=getchar();
        }
    }
    inline void decode(int mask){
        for (int i=0;i<l1;++i){
            mask=(mask*131+i)%l1;
            swap(s1[i],s1[mask]);
        }
    }
    inline void rotate(node* &o,int d){
        node *k=o->ch[d^1];o->ch[d^1]=k->ch[d];k->ch[d]=o;
        o->updata();k->updata();o=k;}
    void ins(node* &o){
        if (o==NULL){
            o=&que[qt++];
            o->po=le;o->r=rand();
            o->ch[0]=o->ch[1]=NULL;
            o->sz=1;
        }else{
            int d=o->cmp(0);ins(o->ch[d]);
            if (o->ch[d]->r > o->r) rotate(o,d^1);
            o->updata();
        }
    }
    int rank(node *o){
        if (o==NULL) return 0;
        int d=o->cmp(1);
        if (d==-1) return (o->ch[0]==NULL ? 0 : o->ch[0]->sz);
        if (!d) return rank(o->ch[0]);
        else return (o->ch[0]==NULL ? 0 : o->ch[0]->sz)+1+rank(o->ch[1]);
    }
    int main(){
        int i,j,m,ans,mask=0;
        scanf("%d",&m);in();
        for (mi[0]=1LL,i=1;i<N;++i) mi[i]=mi[i-1]*p;
        for (i=0;i<l1;++i){
            ha[le]=(le ? ha[le-1] : 0LL)+(UL)(s1[i]-'A')*mi[le];
            ss[le++]=s1[i];ins(rt);
        }while(m--){
            in();
            if (s1[0]=='A'){
                in();decode(mask);
                for (i=0;i<l1;++i){
                    ha[le]=ha[le-1]+(UL)(s1[i]-'A')*mi[le];
                    ss[le++]=s1[i];
                    ins(rt);
                }
            }else{
                in();decode(mask);
                for (i=0;i<l1;++i)
                    ha1[i]=(i ? ha1[i-1] : 0LL)+(UL)(s1[i]-'A')*mi[i];
                ans=-rank(rt);
                for (i=l1;i;--i) s1[i]=s1[i-1];
                s1[0]=up+'A';++l1;
                for (i=0;i<l1;++i)
                    ha1[i]=(i ? ha1[i-1] : 0LL)+(UL)(s1[i]-'A')*mi[i];
                ans+=rank(rt);
                mask^=ans;printf("%d
    ",ans);
            }
        }
    }
    View Code
  • 相关阅读:
    ELF和a.out文件格式的比较
    vim常用命令
    安装linux各种桌面环境
    使用virt-manager创建和管理虚拟机
    第一天 纪念一下
    i节点,容易被人遗忘的节点
    【Linux】服务器之间的免密登录脚本
    【python】python调用shell方法
    【ansible】ansible部署方式以及部署包
    【AWS】亚马逊云常用服务解释
  • 原文地址:https://www.cnblogs.com/Rivendell/p/4675879.html
Copyright © 2020-2023  润新知