zoukankan      html  css  js  c++  java
  • dtoi4720 区间

     题意:

         求已知序列的所有本质不同的子区间的最大值之和。

    题解:

         对于每一个位置i,我们需要计算出最短的区间[i,j],使得[i,j]的字符串没有被算过,那么[i,j+1],[i,j+2],[i,j+3]...[i,n]都不会被算过。

         统计答案很容易,方法应该也不少。我的做法是定义每一个点的父亲为后面第一个比它大的位置,然后倍增一下再计算一下就可以算出答案。

         接下来就是如何求出上述区间,其实就是需要求出一个最小的值a,满足所有后缀j(j<i)与后缀i的最长公共前缀小于a。

         然后我考场上以为两个log是可以过的,就直接写了个二分,然后SA上再来了个二分,于是愉快的TLE了。

         后来想卡常,但是怎么都卡不过去只好又写了一大堆代码改成了一个log的做法,具体如下

         其实我们只需要知道前i-1个后缀中在SA上位置最接近第i个后缀在SA上的位置的那左右两个即可,然后用rmq求一下height的最小值即可。

         线段树维护它写着写着,代码就5.6k了

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    using namespace std;
    const int INF=1313331331;
    int T,n,a[200002],lgg[200002],fa[22][200002],q[200002],len,tax[200002],sa[200002],rk[200002],cnt;
    int h[22][200002],Min[22][200002],las[200002],tp[200002],head[200002],x,y;
    unsigned long long has[200002],cf[200002];
    long long w[200002];
    typedef struct{
        int to,nex;
    }P;
    P p[200002];
    typedef struct{
        int Max,Min,f1,f2;
    }XDS;
    XDS xds[800002];
    void add(int x,int y){
        p[++cnt].to=y;p[cnt].nex=head[x];head[x]=cnt;
    }
    bool cmp(int x,int y){
        return (a[x]<a[y]);
    }
    inline bool pd(int x,int y,int l,int r){
        if (x<l)return (has[y]-has[x-1])*cf[l-x]==(has[r]-has[l-1]);
        else return (has[y]-has[x-1])==(has[r]-has[l-1])*cf[x-l];
    }
    inline int minh(int x,int y){
        int len=y-x+1;
        return min(h[lgg[len]][x],h[lgg[len]][y-(1<<lgg[len])+1]);
    }
    inline int bj(int x,int y){
        int lef=0,righ=min(n-x+1,n-y+1),mid;
        while(lef<righ)
        {
            mid=(lef+righ+1)/2;
            if (pd(x,x+mid-1,y,y+mid-1))lef=mid;else righ=mid-1;
        }
        return lef;
    }
    int read(){
        int f=0;char ch=getchar();
        while(ch<'0' || ch>'9')ch=getchar();
        while(ch>='0' && ch<='9'){f=f*10+ch-48;ch=getchar();}
        return f;
    }
    void pushdown(int root){
        if (xds[root].f1)
        {
            if (xds[root].f1>xds[root*2].Max)xds[root*2].Max=xds[root].f1;
            if (xds[root].f1>xds[root*2+1].Max)xds[root*2+1].Max=xds[root].f1;
            if (!xds[root*2].f1 || xds[root].f1>xds[root*2].f1)xds[root*2].f1=xds[root].f1;
            if (!xds[root*2+1].f1 || xds[root].f1>xds[root*2+1].f1)xds[root*2+1].f1=xds[root].f1;
            xds[root].f1=0;
        }
        if (xds[root].f2)
        {
            if (xds[root].f2<xds[root*2].Min)xds[root*2].Min=xds[root].f2;
            if (xds[root].f2<xds[root*2+1].Min)xds[root*2+1].Min=xds[root].f2;
            if (!xds[root*2].f2 || xds[root].f2<xds[root*2].f2)xds[root*2].f2=xds[root].f2;
            if (!xds[root*2+1].f2 || xds[root].f2<xds[root*2+1].f2)xds[root*2+1].f2=xds[root].f2;
            xds[root].f2=0;
        }
    }
    void build(int root,int begin,int end){
        xds[root].f1=xds[root].f2=0;
        if (begin==end)
        {
            xds[root].Max=-1e9;xds[root].Min=1e9;
            return;
        }
        int mid=(begin+end)/2;
        build(root*2,begin,mid);build(root*2+1,mid+1,end);
        xds[root].Max=max(xds[root*2].Max,xds[root*2+1].Max);
        xds[root].Min=min(xds[root*2].Min,xds[root*2+1].Min);
    }
    void chaxun(int root,int begin,int end,int wz){
        if (begin>wz || end<wz)return;
        if (begin==end)
        {
            x=xds[root].Max;y=xds[root].Min;return;
        }
        int mid=(begin+end)/2;pushdown(root);
        chaxun(root*2,begin,mid,wz);chaxun(root*2+1,mid+1,end,wz);
    }
    void gxmax(int root,int begin,int end,int begin2,int end2,int z){
        if (begin>end2 || end<begin2)return;
        if (begin>=begin2 && end<=end2)
        {
            if (z>xds[root].Max)xds[root].Max=z;
            if (!xds[root].f1 || z>xds[root].f1)xds[root].f1=z;
            return;
        }
        int mid=(begin+end)/2;pushdown(root);
        gxmax(root*2,begin,mid,begin2,end2,z);gxmax(root*2+1,mid+1,end,begin2,end2,z);
        xds[root].Max=max(xds[root*2].Max,xds[root*2+1].Max);
    }
    void gxmin(int root,int begin,int end,int begin2,int end2,int z){
        if (begin>end2 || end<begin2)return;
        if (begin>=begin2 && end<=end2)
        {
            if (z<xds[root].Min)xds[root].Min=z;
            if (!xds[root].f2 || z<xds[root].f2)xds[root].f2=z;
            return;
        }
        int mid=(begin+end)/2;pushdown(root);
        gxmin(root*2,begin,mid,begin2,end2,z);gxmin(root*2+1,mid+1,end,begin2,end2,z);
        xds[root].Min=min(xds[root*2].Min,xds[root*2+1].Min);
    }
    int main()
    {
        for (int i=1;i<=200000;i++)
        for (int j=0;(1<<j)<=i;j++)lgg[i]=j;
        cf[0]=1;
        for (int i=1;i<=200000;i++)cf[i]=cf[i-1]*INF;
        T=read();
        while(T--)
        {
            n=read();len=0;
            for (int i=1;i<=n;i++)a[i]=read();
            for (int i=n;i>=1;i--)
            {
                while(len && a[i]>=a[q[len]])len--;
                if (len)fa[0][i]=q[len];else fa[0][i]=0;
                q[++len]=i;
                if (fa[0][i])w[i]=(long long)a[i]*(fa[0][i]-i)+w[fa[0][i]];
                else w[i]=(long long)a[i]*(n-i+1);
            }
            for (int i=1;i<=17;i++)
            for (int j=1;j<=n;j++)
            fa[i][j]=fa[i-1][fa[i-1][j]];
            for (int i=1;i<=n;i++)
            {
                has[i]=has[i-1]+cf[i-1]*a[i];
                sa[i]=i;
            }
            sort(sa+1,sa+n+1,cmp);
            rk[sa[1]]=1;
            for (int i=2;i<=n;i++)
            if (a[sa[i]]==a[sa[i-1]])rk[sa[i]]=rk[sa[i-1]];else rk[sa[i]]=rk[sa[i-1]]+1;
            for (int i=1;i<=17;i++)
            {
                for (int j=0;j<=n;j++){las[j]=rk[j];tax[j]=0;head[j]=-1;}
                cnt=0;
                for (int j=1;j<=n;j++)
                {
                    if (j+(1<<i-1)>n)tp[j]=0;else tp[j]=j+(1<<i-1);
                    tax[rk[j]]++;add(rk[tp[j]],j);
                }
                for (int j=1;j<=n;j++)tax[j]+=tax[j-1];
                for (int j=n;j>=0;j--)
                for (int k=head[j];k!=-1;k=p[k].nex)
                sa[tax[rk[p[k].to]]--]=p[k].to;
                rk[sa[1]]=1;
                for (int j=2;j<=n;j++)
                if (las[sa[j]]==las[sa[j-1]] && las[tp[sa[j]]]==las[tp[sa[j-1]]])rk[sa[j]]=rk[sa[j-1]];else rk[sa[j]]=rk[sa[j-1]]+1;
            }
            build(1,1,n);
            for (int i=1;i<=n;i++)Min[0][i]=sa[i];
            for (int i=1;i<n;i++)h[0][i]=bj(sa[i],sa[i+1]);
            for (int i=1;i<=17;i++)
            for (int j=1;j<=n;j++)
            {
                if (j+(1<<i-1)<=n)h[i][j]=min(h[i-1][j],h[i-1][j+(1<<i-1)]);
                if (j+(1<<i-1)<=n)Min[i][j]=min(Min[i-1][j],Min[i-1][j+(1<<i-1)]);
            }
            long long ans=0;
            for (int i=1;i<=n;i++)
            {
                int Max=0;
                chaxun(1,1,n,rk[i]);
                if (x>=1 && x<=n && x<rk[i])Max=max(Max,minh(x,rk[i]-1));
                if (y>=1 && y<=n && y>rk[i])Max=max(Max,minh(rk[i],y-1));
                y=i+Max;
                if (y<=n)
                {
                    int x=i;
                    for (int j=17;j>=0;j--)
                    if (fa[j][x]!=0 && fa[j][x]<=y)x=fa[j][x];
                    if (fa[0][x])ans+=(long long)a[x]*(fa[0][x]-y)+w[fa[0][x]];
                    else ans+=(long long)a[x]*(n-y+1);
                }
                if (rk[i]>1)gxmin(1,1,n,1,rk[i]-1,rk[i]);
                if (rk[i]<n)gxmax(1,1,n,rk[i]+1,n,rk[i]);
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    SpringMVC学习指南【笔记6】JSTL标签、函数
    SpringMVC学习指南【笔记5】EL表达式、实现免脚本JSP页面、禁用EL计算的设置
    SpringMVC学习指南【笔记4】数据绑定、表单标签库、转换器、格式化、验证器
    序列封包和序列解包
    python 字符串分割,连接方法
    Jmeter常用插件(转)
    不同的content-type,Jmeter入参不同
    性能监测(CPU)
    正则表达式
    乱码问题
  • 原文地址:https://www.cnblogs.com/1124828077ccj/p/12317971.html
Copyright © 2011-2022 走看看