BZOJ5110 : [CodePlus2017]Yazid 的新生舞會

Claris發表於2017-11-27

顯然每個區間最多隻有一種絕對眾數,故每個數值獨立,考慮列舉每種數值作為絕對眾數然後計算貢獻。

設$s_i$表示前$i$箇中該數值的出現次數,則要選擇一對下標$l,r$滿足:

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

根據數字出現位置,假設它出現了$k$次,則可以將序列劃分成$k+1$段遞減的等差數列,顯然同一段等差數列之間不會有任何貢獻。

那麼從左往右列舉每一段,用樹狀陣列維護每種$2s_i-i$的出現次數即可。

時間複雜度$O(n\log 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;
}

  

相關文章