zoukankan      html  css  js  c++  java
  • 51Nod1592 数列积


    题目看这里
    无比暴力的大分块,极端不优美
    听说很多人用莫队水过去了,我还是被最后一个点卡WAing(本地都过了)
    说下解法:
    首先,将整个序列分块,分成n
    将区间分成三个部分:前面多出来的+中间若干整块+后面多出来的
    价值就可以这样计算:中间若干块+前面部分自身价值+后面部分价值+前面和后面与中间产生的价值+前面和后面产生的价值
    分别考虑每一个部分怎么计算
    首先我们需要计算每一个块自身的价值,直接暴力,这一部分是O(nn)
    我们记f[l,r]表示从第l个块到第r个块的价值,就可以写出dp转移式子:

    f[l,r]=f[l+1,r]+f[l,r1]f[l+1,r1]+v[l,r]

    这里面,v[l,r]表示第l个块和第r个块产生的价值,先不考虑这个怎么计算
    再考虑其他的两个东西,我们记g[i,j]表示以i开头,长度为j+1的一个块的价值,显然g[i,j]=0,这个东西也可以用一个式子来转移
    g[i,j]=g[i,j1]+g[i+1,j1]g[i+1,j2]+|a[i]a[i+j]|j

    处理完这个东西还不够,还需要预处理一个东西p[i,j]表示第a[i]与第j块产生的价值
    这个东西因为状态数较多,所以需要每次将两块合起来处理,考虑原来的式子就有
    (aiaj)(ji)=aij+ajiaiiajj

    这样就可以拆成四个东西来处理,我们在考虑第x块和第y块时(x<y),可以先将x和y排序,让后维护三个前缀和:iaiiai(注意,这里已经排序,i无序)
    考虑对于块y中的元素j,我们找到x中的分界点i,使得i前面的都小于a[j],那么就有这样的转移:
    p[j,x]=jaji+iaijaia[j]i

    对于i后面的元素,只需要将上面式子加上负号就可以了
    当我们预处理出p后,自然就得到v[x,y]=i=l[x]r[x]p[i][y]
    这样,我们就得到了p,g,f三个部分
    最后说一下前面和后面产生的价值怎么计算,类似计算p[i,x]的过程,将这一部分排序,让后就是一样的了

    #include<math.h>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define M 250
    #define N 50000
    #define I w[i]
    #define J w[j]
    #define LL unsigned long long
    using namespace std;
    int n,m,c,q,w[N],l[M],r[M];
    LL f[M][M],g[N][M],p[N][M],v[M][M],s[N];
    inline bool c1(int i,int j){ return s[i]<s[j]; }
    inline LL calB(int l,int r){
        LL S=0;
        for(int i=l;i<=r;++i)
            for(int j=i;j<=r;++j)
                S+=(LL)abs((int)s[i]-(int)s[j])*(j-i);
        return S;
    }
    inline LL dp(int l,int r){
        if(l>r) return 0;
        if(~f[l][r]) return f[l][r];
        if(l==r) return f[l][r]=calB(::l[l],::r[r]);
        return f[l][r]=dp(l+1,r)+dp(l,r-1)-dp(l+1,r-1)+v[l][r];
    }
    LL si[N],sa[N],sm[N],S=0;
    inline LL gV(int x,int y){
        LL S=0;
        for(int i=l[x],j=l[y];j<=r[y];++j){
            while(i<=r[x] && s[I]<s[J]) ++i;
            p[J][x]+=J*s[J]*(i-l[x])+(sm[i-1]-sm[l[x]-1])-J*(sa[i-1]-sa[l[x]-1])-s[J]*(si[i-1]-si[l[x]-1]);
            p[J][x]-=J*s[J]*(r[x]-i+1)+(sm[r[x]]-sm[i-1])-J*(sa[r[x]]-sa[i-1])-s[J]*(si[r[x]]-si[i-1]);
            S+=p[J][x];
        }
        for(int i=l[y],j=l[x];j<=r[x];++j){
            while(i<=r[y] && s[I]<s[J]) ++i;
            p[J][y]-=J*s[J]*(i-l[y])+(sm[i-1]-sm[l[y]-1])-J*(sa[i-1]-sa[l[y]-1])-s[J]*(si[i-1]-si[l[y]-1]);
            p[J][y]+=J*s[J]*(r[y]-i+1)+(sm[r[y]]-sm[i-1])-J*(sa[r[y]]-sa[i-1])-s[J]*(si[r[y]]-si[i-1]);
        }
        return S;
    }
    inline LL gp(int i,int j){
        if(j<=0) return g[i][j]=0;
        if(~g[i][j]) return g[i][j];
        return g[i][j]=gp(i,j-1)+gp(i+1,j-1)-gp(i+1,j-2)+abs((int)s[i]-(int)s[i+j])*j;
    }
    inline LL d(int l,int r,int L,int R){
        static LL s[N],w[N],si[N],sa[N],sm[N],S; 
        S=*si=*sm=*sa=0;
        for(int i=l;i<=r;++i) s[i]=::s[i],w[i]=i;
        for(int i=L;i<=R;++i) s[i]=::s[i],w[i]=i;
        sort(w+l,w+r+1,c1); sort(w+L,w+R+1,c1);
        for(int i=l;i<=r;++i){
            si[i]=si[i-1]+w[i];
            sa[i]=sa[i-1]+s[w[i]];
            sm[i]=sm[i-1]+w[i]*s[w[i]];
        }
        for(int i=L;i<=R;++i){
            si[i]=si[i-1]+w[i];
            sa[i]=sa[i-1]+s[w[i]];
            sm[i]=sm[i-1]+w[i]*s[w[i]];
        }
        for(int i=l,j=L;j<=R;++j){
            while(i<=r && s[I]<s[J]) ++i;
            S+=J*s[J]*(i-l)+(sm[i-1]-sm[l-1])-J*(sa[i-1]-sa[l-1])-s[J]*(si[i-1]-si[l-1]);
            S-=J*s[J]*(r-i+1)+(sm[r]-sm[i-1])-J*(sa[r]-sa[i-1])-s[J]*(si[r]-si[i-1]);
        }
        return S;
    }
    inline LL pS(int l,int r,int x,int y){
        return p[r][y]-p[l-1][y]-p[r][x-1]+p[l-1][x-1];
    }
    int main(){
        scanf("%d",&n); m=ceil(sqrt(n)); c=(n-1)/m+1;
        for(int i=1;i<=n;++i) scanf("%llu",s+i),w[i]=i;
        for(int i=1;i<=c;++i) l[i]=r[i-1]+1,r[i]=i*m; 
        r[c]=n;
        for(int i=1;i<=c;++i) sort(w+l[i],w+r[i]+1,c1);
        for(int x=1;x<=c;++x)
            for(int i=l[x];i<=r[x];++i){
                si[i]=si[i-1]+w[i];
                sa[i]=sa[i-1]+s[w[i]];
                sm[i]=sm[i-1]+w[i]*s[w[i]];
            }
        for(int i=1;i<=c;++i) for(int j=i+1;j<=c;++j) v[i][j]=gV(i,j);
        memset(f,-1,sizeof f); dp(1,m); memset(g,-1,sizeof g);
        for(int i=1;i<=n;++i) gp(i,min(m,n-i+1));
        for(int i=1;i<=n;++i) for(int j=1;j<=c;++j) p[i][j]+=p[i-1][j]+p[i][j-1]-p[i-1][j-1]; 
        scanf("%d",&q);
        for(int L,R;q--;){
            scanf("%d%d",&L,&R);
            int l1=lower_bound(l+1,l+1+c,L+1)-l-1;
            int r1=lower_bound(r+1,r+1+c,R)-r;
            if(l1==r1){ printf("%llu
    ",g[L][R-L]); }
            else if(l1==r1-1) printf("%llu
    ",g[L][r[l1]-L]+g[l[r1]][R-l[r1]]+d(L,r[l1],l[r1],R));
            else printf("%llu
    ",f[l1+1][r1-1]+g[L][r[l1]-L]+g[l[r1]][R-l[r1]]+d(L,r[l1],l[r1],R)+pS(L,r[l1],l1+1,r1-1)+pS(l[r1],R,l1+1,r1-1));
        }
    }
  • 相关阅读:
    windows 10 安装可视化mycat
    YYModel 源码解读(二)之NSObject+YYModel.h (1)
    NSCharacter​Set 使用说明
    YYModel 源码解读(二)之YYClassInfo.h (3)
    Cocoa深入学习:NSOperationQueue、NSRunLoop和线程安全 (转)
    Swift 必备开发库 (高级篇) (转)
    YYModel 源码解读(二)之YYClassInfo.h (2)
    YYModel 源码解读(二)之YYClassInfo.h (1)
    Runtime应用防止按钮连续点击 (转)
    YYModel 源码解读(一)之YYModel.h
  • 原文地址:https://www.cnblogs.com/Extended-Ash/p/9477074.html
Copyright © 2011-2022 走看看