給出 $1$ 到 $n$ 的乙個排列($n\le 10^5$),記做 $a_1, a_2, \dots, a_n$ 。(注:原題面表述為:「給定 $n$ 個互不相同且不超過 $n$ 的整數」,並未指明 $a_i$ 是正數,屬描述不確切,實際題意如此。見管理員賽後發的題解)求所有可能的區間中前 $k$ ($k\le \min(n,50)$)大的數之和的總和,對於長度不足 $k$ 的區間則全部累加。(注:前 $k$ 大是指「最大的 $k$ 個」)
這是一道「標準的」區間統計類問題。不難想到思路:考慮 $a_i$ 在多少個區間內能成為前 $k$ 大的數之一。
進一步轉化成:
對每個數 $a_i$,求它 前面/後面 離它最近且比它大的 $k$ 個數的下標。這個問題把我難住了。看了管理員的題解後,學到正解如下。
按 $a_i$ 從小到大的順序求解。原因在於:若 $a_j < a_i$ 則 $a_j$ 對 $a_i$ 的結果毫無影響,故而按此順序求解,求出 $a_i$ 對應的答案過後便可將 $a_i$ 刪除。不難想到,可以用「雙向鍊錶」來維護原序列;每次向前 $k$ 跳,再向後 $k$ 跳即可。複雜度 $o(nk)$ 。
我並未手寫雙向鍊錶,而是用了std::list
。我對std::list
的介面不熟悉,這次又到 cppreference.com 上溫習了一下。
這道題用std::list
要注意的點有:
std::list::iterator
屬於bidirectional iterator,僅支援++
和--
運算,不能加/減乙個整數也不能兩個 iterator 做差。
要注意區別std::list::iterator
和std::list::reverse_iterator
這兩個型別。二者貌似是可以互相做型別轉換的。例如
std::lista;
std::::iterator it=a.begin();
std::::reverse_iterator rit = a.rend();
std::::reverse_iterator rit2(it);
assert(rit == rit2);
需要注意的是,當 iterator 轉成 reverse_iterator 時,會向前移動一次,即返回的 reverse_iterator object 指向的是原 iterator object 所指向的前一位置。
另外,在宣告 reverse_iterator 時若要做此型別轉換則只能以()
或{}
的方式賦初始值不能以=
的方式(至少 g++ 如此)。
#include using namespace std;
lista;
const int n =1e5+5;
list::iterator iter[n];
int pre[51];
int post[51];
int main()
long long ans =0;
for(int i=1; i<=n; i++);
// cout << "x: "<< *riter << '\n';
while(1)
// cout << *riter<<'\n';
pre[c1] = *riter;
if(c1==k) break;
++c1;
}int c2=1;
auto tmp = iter[i];
while(1)
post[c2]=*tmp;
if(c2==k) break;
++c2;
}assert(c2 <= k);
int pos = *iter[i];
// for(int i=1; i<=c1; i++)
// cout << pre[i] << ' ';
// cout << '\n';
// for(int i=1; i<=c2; i++)
// cout << post[i] << ' ';
// cout << '\n';
pre[0] = pos;
for(int j=1; j<=c1; j++)
a.erase(iter[i]);
}cout << ans << '\n';
return 0;
}
hihocoder 字尾陣列
時間限制 5000ms 單點時限 1000ms 記憶體限制 256mb 描述小hi平時的一大興趣愛好就是演奏鋼琴。我們知道乙個 旋律被表示為長度為 n 的數構成的數列。小hi在練習過很多曲子以後發現很多作品自身包含一樣的旋律。旋律是一段連續的數列,相似的旋律在原數列可重疊。比如在1 2 3 2 3 ...
B 迴圈陣列 HihoCoder 1704
hihocoder 1704 給定包含n個整數的陣列a1,a2,an,你可以選擇任意乙個ai,將ai旋轉到陣列第一項,即將陣列變成 ai,ai 1,ai 2,an,a1,a2,ai 1 現在小hi希望旋轉之後的陣列滿足 對於任意k 1 i n 前k項的和都是正數。例如對於a 3,5,2,2,3,0 ...
HihoCoder 1523 陣列重排2
給定乙個1 n的排列a1,a2,an,每次操作小hi可以選擇乙個數,把它放到陣列的最左邊。請計算小hi最少進行幾次操作就能使得新陣列是遞增排列的。input 第一行包含乙個整數n。第二行包含n個兩兩不同整數a1,a2,an。1 ai n 對於60 的資料 1 n 20 對於100 的資料 1 n 1...