zoukankan      html  css  js  c++  java
  • [LOJ 6253] Yazid 的新生舞会

    link

    $solution:$

    不知道为什么别人的代码能写的非常短,难道就是写差分的好处?

    这种题肯定是算每个众数的贡献,考虑通过暴力众数求出个数。

    现在考虑众数 $x$ ,则在序列 $a$ 中将等于 $x$ 的置为 $1$ ,否则置为 $-1$,令为序列 $A$ 。设 $S_i=sum_{k=1}^i A_k$。

    若 $[l,r]$ 是满足题意的区间,则 $S_r>S_{l-1}$ ,所以对于每个众数 $x$ ,求出满足 $i>j,S_i>S_j$ 的方案数,直接求二维偏序即可,时间复杂度 $O(n^2log n)$ ,并不能通过本题。

    但是,我们能发现一个性质,在每个 $A$ 中只会有很少的 $1$ ,与很多的 $-1$ 出现,因为 $1$ 只能在 $A$ 中出现 $n$ 次。对于连续 $-1$ 段来说不可能 $l,r$ 均在其中,并且它们的 $S$ 值是每次减一,所以考虑将它们合为一个,其 $S$ 的范围为 $[L,R]$ ,可以简单发现连续段个数与 $n$ 同阶。

    考虑将 $-1$ 连续段中作为右端点对答案的贡献,设 $l,r$ 为连续段的左右端点,$L,R$ 为 $S$ 的范围,$C_i$ 为满足 $S_k=i,kin [0,i)$ 的个数。

    则容易推出$$Ans=sum_{i=-n}^{L-1} C_i imes (R-L+1)+sum_{i=L}^R C_i imes (R-i)\=sum_{i=-n}^{L-1} C_i imes (R-L+1)+sum_{i=L}^R C_i-sum_{i=L}^R C_i imes i$$

    发现 $sum_{i=-n}^{L-1} C_i imes (R-L+1)$ 这两个式子直接线段树区间加法维护即可,而 $sum_{i=L}^R C_i imes i$ 直接线段树上维护等差数列即可。

    现在考虑完右端点在 $-1$ 的情况,而右端点在 $1$ 时直接线段树查询 $[-n,S_{i}-1]$ 即可。

    因为区间段与 $n$ 同阶,所以时间复杂度为 $O(nlog n)$ 。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #define int long long
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=1000001;
    int n,a[MAXN];
    vector<int> ve[MAXN];
    struct Segment1{
        int Ans[MAXN<<2],Beg[MAXN<<2],D[MAXN<<2],qx[MAXN],qy[MAXN],qbe[MAXN],qd[MAXN],tot;
        inline void clear(){
            for(int i=1;i<=tot;i++) Modify(1,0,2*n,qx[i],qy[i],-qbe[i],-qd[i]);
            tot=0;
        }
        inline void pushdown(int k,int l,int r){
            int mid=l+r>>1;
            if(!Beg[k]&&!D[k]) return;
            Ans[k<<1]+=Beg[k]*(mid-l+1)+((((mid-l+1)*(mid-l))/2)*D[k]);
            Ans[k<<1|1]+=Beg[k]*(r-mid)+((((r+mid-2*l+1)*(r-mid))/2)*D[k]);
            Beg[k<<1]+=Beg[k],Beg[k<<1|1]+=Beg[k]+(mid+1-l)*D[k];
            D[k<<1]+=D[k],D[k<<1|1]+=D[k];
            Beg[k]=D[k]=0;
            return;
        }
        inline void Modify(int k,int l,int r,int x,int y,int be,int d){
            if(x<=l&&r<=y){
                Ans[k]+=((r-l+1)*be)+(((((l+r)*(r-l+1))/2)-(x*(r-l+1)))*d);
                Beg[k]+=(be+(l-x)*d);
                D[k]+=d;
                return; 
            }
            pushdown(k,l,r);
            int mid=l+r>>1;
            if(x<=mid) Modify(k<<1,l,mid,x,y,be,d);
            if(mid<y) Modify(k<<1|1,mid+1,r,x,y,be,d);
            Ans[k]=Ans[k<<1]+Ans[k<<1|1];
            return;
        }
        inline int Query(int k,int l,int r,int x,int y){
            if(x<=l&&r<=y) return Ans[k];
            pushdown(k,l,r);
            int mid=l+r>>1,res=0;
            if(x<=mid) res+=Query(k<<1,l,mid,x,y);
            if(mid<y) res+=Query(k<<1|1,mid+1,r,x,y);
            Ans[k]=Ans[k<<1]+Ans[k<<1|1];return res;
        }
        inline void add(int x,int y,int be,int d){
            qx[++tot]=x+n;qy[tot]=y+n;qbe[tot]=be,qd[tot]=d;
            Modify(1,0,2*n,x+n,y+n,be,d);return;
        }
        inline int Q(int x,int y){
            return Query(1,0,2*n,x+n,y+n);
        }
    }segment1;
    struct Segment2{
        int Ans[MAXN<<2],tag[MAXN<<2];
        int qx[MAXN],qy[MAXN],qw[MAXN],tot;
        inline void clear(){
            for(int i=1;i<=tot;i++) Modify(1,0,2*n,qx[i],qy[i],-qw[i]);
            tot=0;
        }
        inline void pushdown(int k,int l,int r){
            if(!tag[k]) return;
            int mid=l+r>>1;
            Ans[k<<1]+=tag[k]*(mid-l+1);Ans[k<<1|1]+=tag[k]*(r-mid);
            tag[k<<1]+=tag[k],tag[k<<1|1]+=tag[k];
            tag[k]=0;return;
        }
        inline void Modify(int k,int l,int r,int x,int y,int w){
            if(x<=l&&r<=y){
                tag[k]+=w;
                Ans[k]+=(r-l+1)*w;return;
            }
            pushdown(k,l,r);
            int mid=l+r>>1;
            if(x<=mid) Modify(k<<1,l,mid,x,y,w);
            if(mid<y) Modify(k<<1|1,mid+1,r,x,y,w);
            Ans[k]=Ans[k<<1]+Ans[k<<1|1];return;
        }
        inline int Query(int k,int l,int r,int x,int y){
            if(x<=l&&r<=y) return Ans[k];
            pushdown(k,l,r);
            int mid=l+r>>1,res=0;
            if(x<=mid) res+=Query(k<<1,l,mid,x,y);
            if(mid<y) res+=Query(k<<1|1,mid+1,r,x,y);
            Ans[k]=Ans[k<<1]+Ans[k<<1|1];return res;
        }
        inline void add(int x,int y,int w){
            qx[++tot]=x+n,qy[tot]=y+n,qw[tot]=w;
            Modify(1,0,2*n,x+n,y+n,w);return;
        }
        inline int Q(int x,int y){
            return Query(1,0,2*n,x+n,y+n);
        }
    }segment2;
    int Ans;
    signed main(){
    //    freopen("1.in","r",stdin);
        n=read();read();
        for(int i=1;i<=n;i++) a[i]=read(),ve[a[i]].push_back(i);
        for(int i=0;i<n;i++){
            int siz=ve[i].size();
            if(!siz) continue;
            int l=1,r=-1;
            segment1.clear();
            segment2.clear();
            segment1.add(0,0,0,1);
            segment2.add(0,0,1);
            for(int j=0;j<siz;j++){
                int u=ve[i][j];
                r=u-1;
                if(j!=0) l=ve[i][j-1]+1;
                else l=1;
                if(l<=r){
                    int L=-l+j*2,R=-r+j*2;
                    if(L>R) swap(L,R);
                    Ans+=segment2.Q(-n,L-1)*(R-L+1);
                    Ans+=R*segment2.Q(L,R);
                    Ans-=segment1.Q(L,R);
                    segment1.add(L,R,L,1);
                    segment2.add(L,R,1);
                }
                int Psum=-u+2*(j+1);
                Ans+=segment2.Q(-n,Psum-1);
                segment1.add(Psum,Psum,Psum,1);
                segment2.add(Psum,Psum,1);
            }
            l=ve[i][siz-1]+1,r=n;
            if(l<=r){
                int L=-l+siz*2,R=-r+siz*2;
                if(L>R) swap(L,R);
                Ans+=segment2.Q(-n,L-1)*(R-L+1);
                Ans+=R*segment2.Q(L,R);;
                Ans-=segment1.Q(L,R);
                segment1.add(L,R,L,1);
                segment2.add(L,R,1);
            }
        }printf("%lld
    ",Ans);return 0;
    }
    View Code
  • 相关阅读:
    Boost练习程序(强制转换)
    4873279(1002)
    A+B Problem(1000)
    STL练习程序(去除相同元素)
    Boost练习程序(智能指针)
    Sql技巧总结
    MySql Show Status详解
    mysql show status调优
    mysql decimal、numeric数据类型
    Apache Thrift学习小记
  • 原文地址:https://www.cnblogs.com/si-rui-yang/p/11234075.html
Copyright © 2011-2022 走看看