顯然每個區間最多隻有一種絕對眾數,故每個數值獨立,考慮列舉每種數值作為絕對眾數然後計算貢獻。
設$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; }