1. 程式人生 > >小Z的襪子【莫隊演算法】

小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<b.r;
  return a.l<b.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還慢。。。