[JZOJ5951] 鋒芒畢露 (【CodeChef June Challenge 2014】Sereja and Arcs)【平衡規劃】【計數】【樹狀陣列】
Description
給定一個長度為n的顏色序列a
求四元組
的數量
Solution
以下為了方便說明,用大寫字母表示一種顏色,
就是一個合法四元組
直接計算比較繁瑣,考慮補集轉化
如果我們能算出 和 的數量,那就可以求出 的數量了
考慮計算 ,這其實就相當於把 的限制去掉了。
列舉 ,計算兩邊有多少對 ,再減掉y,q相同顏色的,乘上左邊x的數量就是答案
計算兩邊有多少對 ,可以維護增量,從左向右掃的時候,每向右一個位置,相當於將一個位置從右邊移到了左邊,加上多出來的減去刪掉的貢獻即可。
這樣 就算完了
考慮如何計算
直接用資料結構好像沒有什麼好的辦法,於是往平衡規劃的方向來想。
我們設定一個閾值 ,出現次數小於等於K的顏色記作Q,大於K的顏色記作P
那麼P的總數不超過
,Q的大小的平方和不超過
對於四元組分類討論
-
:列舉顏色P,從左到右掃,設當前掃到位置 ,i之前P的出現次數為 ,它在顏色a[i]中是第t個,那麼明顯貢獻就是 只需要用一個桶記一下i前面每個顏色的j的 和即可。時間複雜度
-
:同樣列舉顏色P,從左到右掃,位置i的貢獻就是 ,把式子拆開,發現只需要多維護s[]的平方和即可。時間複雜度
-
:此時所有二元組 的總數不超過nK,那麼我們將所有二元組 看做二維平面上的點,現在就相當於求點 的對數,就變成二維數點問題,將所有點按照縱座標從小到大掃一遍,樹狀陣列查詢即可。時間複雜度
總複雜度為 ,容易發現當 時總複雜度最小,為
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);