書本配套oj
本校oj
st表使用說明:
數列區間最大值
題意簡述
輸入一串數字,給你 m 個詢問,每次詢問就給你兩個數字 x,y,要求你說出 x 到 y 這段區間內的最大數。
解題思路
st表模板題。
**示例
#include
using
namespace std;
int n,m;
const
int n =
1e5+10;
int st[n][22
],log[n]
;int a[n]
;int
getint()
void
init()
}}intask
(int l,
int r)
intmain()
return0;
}
最敏捷的機械人
題意簡述
wind 設計了很多機械人。但是它們都認為自己是最強的,於是,一場比賽開始了……
機器人們都想知道誰是最敏捷的,於是它們進行了如下乙個比賽。首先,他們面前會有一排共 n 個數,它們比賽看誰能最先把每連續 k 個數中最大和最小值寫下來,當然,這些機械人運算速度都很快,它們比賽的是誰寫得快。
但是 wind 也想知道答案,你能幫助他嗎?
解題思路
st表模板題,不過還要維護一下最小值,多開乙個陣列即可。
**示例
#include
using
namespace std;
int n,m;
const
int n =
1e5+10;
int st[n][22
],log[n]
, st2[n][22
];int a[n]
;int
getint()
void
init()
}}void
ask(
int l,
int r)
intmain()
與眾不同*
題意簡述
a 是某公司的 ceo,每個月都會有員工把公司的盈利資料送給 a,a 是個與眾不同的怪人,a 不注重盈利還是虧本,而是喜歡研究「完美序列」:一段連續的序列滿足序列中的數互不相同。
a 想知道區間 [l,r] 之間最長的完美序列長度。
解題思路
我們可以通過標記陣列在o(n)時間內求出每個位置「作為結束位置」時的最長完美序列長度,以及它的起點。
設last[ x ] 表示 x 上次出現的位置;bgn[ p ]表示以位置 p 為末尾的完美序列的起點位置;len[p] 表示以位置 p 為末尾的完美序列的長度。顯然我們可以在一次遍歷內更新完畢上述三個陣列,o(n)。
那麼對於任意區間[ l , r ],其內的最長完美序列長度僅有 2 種可能,一種是終點在區間內,起點不在;另一種是起點和終點都在區間內。此時我們已經可以通過一次遍歷來求答案了,但是複雜度最差o(n),不可取。由於bgn是單調遞增的,所以對於某個位置 pos,[ l , pos-1] 所有位置上的起點都小於 l,[pos , r]上所有位置上的起點都大於l,那麼我們可以通過st表維護 [pos ,r] 上的最大的 len 值,在o(1)時間內求出,那麼答案就是max(pos-l , ask(pos , r) )。
我們可以通過二分搜尋來查詢 pos ,複雜度 o(log n),根據len陣列構造st表,o(nlogn),總時間複雜度o( (n+m)logn )。
**示例
#include
using
namespace std;
int n,m;
const
int n =
2e5+10;
const
int sz =
2e6+10;
const
int b =
1e6;
/*last[x]為x上一次出現的位置;
bgn[p]為以位置p結尾的起點位置;len[p]為以p結尾的完美序列長度*/
int last[sz]
,bgn[n]
,len[n]
;int a[n]
,log[n]
,st[n][22
];void
init_st()
intask
(int l,
int r)
intbsearch
(int l,
int r,
int x)
return l;
}void
solve()
init_st()
;//建立len陣列的st表
for(
int i =
1,x,y,p,res;i <= m;i++)}
intmain()
天才的記憶
**示例:模板模板,題面和思路不說了。
#include
using
namespace std;
int n,m;
const
int n =
2e5+10;
int st[n][22
],log[n]
;int a[n]
;int
getint()
void
init()
}}intask
(int l,
int r)
intmain()
return0;
}
balanced lineup
**示例:和「敏捷的機械人」一樣,都是要維護最大以及最小值。
#include
using
namespace std;
int n,m;
const
int n =
1e5+10;
int st[n][22
],log[n]
, st2[n][22
];int a[n]
;int
getint()
void
init()
}}void
ask(
int l,
int r)
intmain()
return0;
}
選擇客棧*
題意描述
麗江河邊有 n 家很有特色的客棧,客棧按照其位置順序從 1 到 n 編號。
每家客棧都按照某一種色調進行裝飾(總共 k 種,用整數 0 k−1 表示),且每家客棧都設有一家咖啡店,每家咖啡店均有各自的最低消費。
兩位遊客一起去麗江旅遊,他們喜歡相同的色調,又想嘗試兩個不同的客棧,因此決定分別住在色調相同的兩家客棧中。
晚上,他們打算選擇一家咖啡店喝咖啡,要求咖啡店位於兩人住的兩家客棧之間(包括他們住的客棧),且咖啡店的最低消費不超過 p 。
他們想知道總共有多少種選擇住宿的方案,保證晚上可以找到一家最低消費不超過 p 元的咖啡店小聚。
解題思路
沒看正解是啥,我沒用到st表,不過倒是用到了求rmq的步驟。
共三個輔助陣列,col[k] 表示當前第k種顏色客棧的數量;val[x]表示客棧x的最低消費;mip[x]表示 [x, n] 內第乙個最低消費小於等於 p 元的客棧位置。
如果第乙個人入住客棧x,第二個人能夠入住的旅店的位置一定是大於等於mip[x]的,並且要顏色和 x 相同,即col[ a[i] ]種選擇方案。所以我們只需要從前往後順序遍歷一遍並統計答案即可,複雜度o(n)。
**示例
#include
using
namespace std;
const
int n =
2e6+10;
const
int k =
1e4+10;
typedef
long
long ll;
int col[k]
;int n,m,p;
int a[n]
,val[n]
;int
getint()
int mip[n]
;void
solve()
int pre =
1; ll ans =0;
for(
int i =
1;i <= n;i++
)printf
("%lld\n"
,ans);}
intmain()
solve()
;return0;
}
二維RMQ問題
前置知識 一維rmq及其拓展 對於乙個n m n m的矩陣,每個格仔有乙個值,有q q個詢問,每次詢問你乙個子矩陣中的最大值。1 n,m 500,q 1061 n,m 500 q 1 06每次花子矩陣大小的複雜度去查詢。複雜度最壞o q n m o q n m 我們用n n棵線段樹或者樹狀陣列來維護...
關於RMQ問題的一些感悟
一般就是4種解決辦法吧。1 線段樹 2 樹狀陣列 3 st表 4 差分 樹狀陣列是一種很輕便的工具,編碼簡單,常數小,缺點是只能求和。不同版本的樹狀陣列能實現不同組合的單點,區間,詢問,修改。時間複雜度都是o logn st表也是一種很輕便的工具,編碼簡單,常數小,缺點是只能求最值,而且是離線演算法...
面試易錯題 陷阱題集一
1.oj 設計乙個函式sum n 1 2 n,假設sum n 不超過整型數表示範圍。錯誤解法 int sum n 錯誤在於 n n 1 時可能已經超出了整型數的表示範圍,造成溢位錯誤。int sum n 2.美圖 請寫出下面程式的執行結果。void func void printf s dst 易錯...