小Z的袜子【莫队算法】

莫队算法最经典的题目吧。
其实莫队算法比较像暴力。(你不写曼哈顿最小生成树还说人家暴力(逃
好吧,其实我用的不是标准的莫队算法,而是类似一种分块的思想
将块的大小保持在sqrt(n),可以证明时间复杂度为O(n^1.5)
貌似可以根据已知[l,r]的信息是否可以O(1)的推出[l+1,r]和[l-1,r]的信息来判断是否试用莫队算法。
对于小Z的袜子这道题,我们先离线的排序询问,左端点第一关键字,右端点第二关键字
将1~n的块分好

block=(int)sqrt(n);
  for(int i=1;i<=n;i++)belong[i]=(i-1)/block+1;

排序

bool cmp(Node a,Node b){
  if(belong[a.l]==belong[b.l])return a.r;
  return a.l; 
}

一个区间内颜色相同的概率为:
设这个区间每个颜色的个数和记为a[i],则答案为 sigmaC(a[i],2)/C(r-l+1,2)
上下的2!可以约去,变为sigma(a[i] * (a[i]-1))/n*(n-1)
对于每次+1的操作会增加2*pre(a[i]) nowa[i]=pre[a[i]+1
发现如果使用nowa[i]-1的话会出现0*-1增加一是1*0的情况,所以决定不删去2!操作,直接加上prea[i],也就是ans+=后,a[i]++
同理可以分析出减法操作是 cnt减1后 ans-=
代码长这样:

    while(r<q[i].r)ans+=cnt[a[++r]]++;
    while(r>q[i].r)ans-=--cnt[a[r--]];
    while(l<q[i].l)ans-=--cnt[a[l++]];
    while(l>q[i].l)ans+=cnt[a[--l]]++;

其他需要注意的就是求个gcd,约分了。
并不清晰为甚么po大爷的分块跑500多秒,而我比他写的MMST还慢。。。

你可能感兴趣的:(莫队算法,进击的OIer)