• BZOJ5110 : [CodePlus2017]Yazid 的新生舞会


    显然每个区间最多只有一种绝对众数,故每个数值独立,考虑枚举每种数值作为绝对众数然后计算贡献。

    设$s_i$表示前$i$个中该数值的出现次数,则要选择一对下标$l,r$满足:

    • $0leq l<rleq n$。
    • $2s_r-r>2s_l-l$。

    根据数字出现位置,假设它出现了$k$次,则可以将序列划分成$k+1$段递减的等差数列,显然同一段等差数列之间不会有任何贡献。

    那么从左往右枚举每一段,用树状数组维护每种$2s_i-i$的出现次数即可。

    时间复杂度$O(nlog n)$。

    #include<cstdio>
    typedef long long ll;
    const int N=500010,M=N<<1,BUF=N*10;
    int n,lim,m,i,j,x,g[N],nxt[N],q[N];ll fa[M],fb[M],fc[M],ans;char Buf[BUF],*buf=Buf;
    inline void read(int&a){for(a=0;*buf<48;buf++);while(*buf>47)a=a*10+*buf++-48;}
    inline void add(int x,int p){
      ll y=1LL*x*x-3*x+2;
      for(int i=x;i<=lim;i+=i&-i)fa[i]+=p,fb[i]+=x*p,fc[i]+=y*p;
    }
    inline ll ask(int x){
      ll a=0,b=0,c=0;
      for(int i=x;i>0;i-=i&-i)a+=fa[i],b+=fb[i],c+=fc[i];
      return a*(1LL*x*x+3*x)-b*2*x+c;
    }
    inline void work(int l,int r,int v,int p){
      r-=l;
      l=v-r+n+1;
      r=v+n+1;
      if(p)add(l,-1),add(r+1,1);else ans+=ask(r-1)-ask(l-2),add(l,1),add(r+1,-1);
    }
    int main(){
      fread(Buf,1,BUF,stdin);read(n),read(i);
      lim=n*2+1;
      for(i=1;i<=n;i++)read(x),nxt[i]=g[x],g[x]=i;
      q[0]=n+1;
      for(i=0;i<=n;i++)if(g[i]){
        for(m=0,j=g[i];j;j=nxt[j])q[++m]=j;
        q[m+1]=0;
        for(j=m+1;j;j--)work(q[j],q[j-1]-1,(m-j+1)*2-q[j],0);
        for(j=m+1;j;j--)work(q[j],q[j-1]-1,(m-j+1)*2-q[j],1);
      }
      return printf("%lld",ans/2),0;
    }
    

      

  • 相关阅读:
    [最新]制作u盘引导安装ubuntu11.04
    js记录
    下面的代码有什么不妥之处
    Oracle常用命令
    蓝天下,献给你,html5
    无意义的小东西
    sql中,把varchar类型转换为int型,然后进行排序
    身边的人,来来去去
    不一定能写出来的求素数问题
    写在第一百篇博客之际
  • 原文地址:https://www.cnblogs.com/clrs97/p/7906124.html
Copyright © 2020-2023  润新知