武漢大學2023年新生程式設計競賽

2021-10-10 18:32:21 字數 3027 閱讀 6913

e 倉鼠與珂朵莉

主席樹 + 啟發式合併思想

題意:

給你乙個長度為n的陣列, 每次操作選擇乙個區間 [l,

r]

[l, r]

[l,r

] 然後問 選擇乙個數 k

kk 然就出 k

kk 再這個區間的次數的乘積。

題解:

如果給你乙個區間[l,

r]

[l, r]

[l,r

] 對於暴力的求法一般是列舉每個數, 再去查詢這個數出現了幾次,然後算出最大的貢獻。

這樣對於每次詢問都是 o(n

)o(n)

o(n)

的複雜度。

如果我們每次只找 出現一次 且最大的數, 出現兩次且最大的數, 出現三次且最大的數…………

假設已經知道看出現一次且最大的數, 出現兩次且最大的數…………

那麼列舉的時間複雜度為 1+2

+3+4

…………

=r−l

+1

1 + 2 + 3 + 4 ………… = r - l + 1

1+2+3+

4………

…=r−

l+1 大概是 (lo

gn)2

(logn)^2

(logn)

2 左右,但是這樣有個問題?

如何找到出現一次且最大的數, 出現兩次且最大數?

我想了很久好像沒有可行的方法。

但是, 仔細想一下, 你會發現, 如果最大值出現了 x

xx 次也就意味著小於 x

xx 次的就不用再找,那麼也就意味著

找 第乙個比 最大值小 且 出現次數大於 x

xx 次的數。

那麼這樣每次的複雜度就是 x

1

…………

x1 < x2 < x3 < x4 …………

x1…………

(x 1x1

x1表示最大值出現的次數 x2x2

x2表示第乙個比最大小的數出現的次數…………)

每次尋找都比之前的大,是不是啟發式合併的複雜度啊, 哦好像是的

那麼怎麼找到這個每個數出現的次數呢?

這裡可以用到主席樹了

主席樹沒法確定單個數字出現的個數只能求出這個區間有多少個數, 當這個區間的總個數都小於 x1x1

x1那麼肯定沒有單點資訊大於 x1x1

x1, 在維護乙個每個數 在 [1,

r]

[1, r]

[1,r

] 區間出現的 重要程度的最大值, 如果區間重要程度的最大值都小於 直接找的答案也就沒用必要再找, 這樣兩個限制大概率保證了每個數出現的個數了。

所以總共的時間複雜度為 q∗l

og(n

)∗lo

g(n)

q * log(n) * log(n)

q∗log(

n)∗l

og(n

)

#include

using namespace std;

const

int n =

1e5+7;

typedef

long

long ll;

struct hjttree[

40* n]

;vector g;

intget_id

(int x)

ll a[n]

, n, q, b[n]

;int rt[n]

, top =1;

#define m (l + r) / 2

void

update

(int pos,

int l,

int r,

int last,

int&now)

if(pos <= m)

update

(pos, l, m, tree[now]

.l, tree[now]

.l);

else

update

(pos, m +

1, r, tree[last]

.r, tree[now]

.r);

tree[now]

.sum =

max(tree[tree[now]

.l].sum, tree[tree[now]

.r].sum);}

ll mx =0;

ll ans =0;

void

query

(int last,

int now,

int l,

int r)

int sumr = tree[tree[now]

.r].cnt - tree[tree[last]

.r].cnt;

int suml = tree[tree[now]

.l].cnt - tree[tree[last]

.l].cnt;

if(sumr > mx && ans < tree[tree[now]

.r].sum)

if(suml > mx && ans < tree[tree[now]

.l].sum)

}int

main()

sort

(g.begin()

, g.

end())

; g.

erase

(unique

(g.begin()

, g.

end())

);for(

int i =

1; i <= n; i++

)int maxn = g.

size()

;for

(int i =

1; i <= n; i++

) ll last =0;

while

(q--

)}

浙江中醫藥大學2018級新生程式設計競賽

題目很簡單,兩個for迴圈巢狀一下,控制下每行左後一位的換行直接輸出就好了。include include include include include includeusing namespace std typedef long long ll typedef unsigned long lo...

2023年廣東省大學生程式設計競賽 H

一看這題就會想到應該是用線段樹處理 一條邊的分出來的兩個部分點編號並不是連續的,這樣很難用線段樹處理 所以我們就想到給點重新編號,dfs一次,按訪問到的點順序給點編號 dfs一條邊的子樹得到的編號肯定是連續,然後我們記錄著這個居間 這樣就可以套線段樹了,by hehele include inclu...

2023年湘潭大學程式設計競賽

a 時間統計 某個實驗需要統計時間,記錄了實驗開始和結束的時間,計算實驗用了多少秒。第一行輸入乙個整數n,表示樣例個數。接下來每組樣例兩行,表示開始時間和結束時間,格式為xdayhh mm ss,x是乙個整數表示第幾天,0 x 20000,hh表示小時,mm表示分鐘,ss表示秒,保證時間合法,結束時...