1. 程式人生 > >[JZOJ5951] 鋒芒畢露 (【CodeChef June Challenge 2014】Sereja and Arcs)【平衡規劃】【計數】【樹狀陣列】

[JZOJ5951] 鋒芒畢露 (【CodeChef June Challenge 2014】Sereja and Arcs)【平衡規劃】【計數】【樹狀陣列】

Description

給定一個長度為n的顏色序列a
求四元組 ( x , y , p , q )

, x < p < y < q , a
[ x ] = a [ y ] , a [
p ] = a [ q ] , a [ x ] ̸ = a [ p ] (x,y,p,q),x<p<y<q,a[x]=a[y],a[p]=a[q],a[x]\not =a[p] 的數量

Solution

以下為了方便說明,用大寫字母表示一種顏色, A B A B ABAB 就是一個合法四元組
直接計算比較繁瑣,考慮補集轉化

如果我們能算出 A B A B + B A A B ABAB+BAAB B A A B BAAB 的數量,那就可以求出 A B A B ABAB 的數量了

考慮計算 A B A B + B A A B ABAB+BAAB ,這其實就相當於把 x < p x<p 的限制去掉了。

列舉 y y ,計算兩邊有多少對 ( p , q ) (p,q) ,再減掉y,q相同顏色的,乘上左邊x的數量就是答案

計算兩邊有多少對 ( p , q ) (p,q) ,可以維護增量,從左向右掃的時候,每向右一個位置,相當於將一個位置從右邊移到了左邊,加上多出來的減去刪掉的貢獻即可。

這樣 O ( n ) O(n) 就算完了

考慮如何計算 B A A B BAAB

直接用資料結構好像沒有什麼好的辦法,於是往平衡規劃的方向來想。

我們設定一個閾值 K K ,出現次數小於等於K的顏色記作Q,大於K的顏色記作P

那麼P的總數不超過 n / K n/K ,Q的大小的平方和不超過 n K nK
對於四元組分類討論

  • P _ _ P P\_\_P :列舉顏色P,從左到右掃,設當前掃到位置 i i ,i之前P的出現次數為 s [ i ] s[i] ,它在顏色a[i]中是第t個,那麼明顯貢獻就是 j = 1 , a [ j ] = a [ i ] , a [ i ] ! = P i 1 s [ j ] ( s i z e [ P ] s [ i ] ) \sum\limits_{j=1,a[j]=a[i],a[i]!=P}^{i-1}s[j]*(size[P]-s[i]) 只需要用一個桶記一下i前面每個顏色的j的 s [ ] s[] 和即可。時間複雜度 O ( n 2 K ) O({n^2\over K})

  • Q P P Q QPPQ :同樣列舉顏色P,從左到右掃,位置i的貢獻就是 j = 1 , a [ j ] = a [ i ] , a [ i ] ! = P i 1 ( s [ i ] s [ j ] 2 ) \sum\limits_{j=1,a[j]=a[i],a[i]!=P}^{i-1}{s[i]-s[j]\choose 2} ,把式子拆開,發現只需要多維護s[]的平方和即可。時間複雜度 O ( n 2 K ) O({n^2\over K})

  • Q 1 Q 2 Q 2 Q 1 Q_1Q_2Q_2Q_1 :此時所有二元組 ( x , y ) , a [ x ] = a [ y ] , s i z e [ a [ x ] ] K (x,y),a[x]=a[y],size[a[x]]\leq K 的總數不超過nK,那麼我們將所有二元組 ( x , y ) (x,y) 看做二維平面上的點,現在就相當於求點 A ( x , y ) , B ( p , q ) , x < p < q < y A(x,y),B(p,q),x<p<q<y 的對數,就變成二維數點問題,將所有點按照縱座標從小到大掃一遍,樹狀陣列查詢即可。時間複雜度 O ( n K log n ) O({nK \log n})

總複雜度為 O ( n 2 K + n K log n ) O({n^2\over K}+nK\log n) ,容易發現當 K = n log n K=\sqrt{n\over \log n} 時總複雜度最小,為 O ( n n log n ) O(n\sqrt{n\log n})

Code

#pragma GCC optimize(2)
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define N 676676
#define mo 19260817
#define LL long long
using namespace std;
int n,a[N],d[N],n1,num;
vector<int> pt[N];
LL ans,c1[N],c2[N],cnt[N],le[N],ny2,c[N];
struct node
{
	int x,y;
	friend bool operator <(node x,node y) 
	{
		return x.y<y.y;
	}
}pr[N*20];
int lowbit(int k)
{
	return k&(-k);