有 \(n\) 個數 \(a_i\) ,他準備將他們依次插入乙個雙端佇列(每次可以在頭或尾插入乙個元素),最後將
整個佇列從尾到頭看成乙個序列,求出最長上公升子串行的長度 。他想知道 , \(l\) 的最大值是多少。
很簡單,考慮乙個數,構造有它的最長上公升子串行
把比他小的放他前面,比他大的放它後面
比他小的最優的就是以某乙個比他小的數為開頭的最長下降子串行的長度
比他大的最優的就是以它為開頭的最長上公升子串行的長度
最後相加取最大值即可
線段樹維護 \(o(n \log n)\)
#include#include#include#define ls (k << 1)
#define rs (ls | 1)
using namespace std;
const int n = 1e5 + 5;
int n , a[n] , f[n] , g[n] , v , seg[n * 4] , b[n];
void build(int l , int r , int k)
int mid = (l + r) >> 1;
build(l , mid , ls) , build(mid + 1 , r , rs);
seg[k] = max(seg[ls] , seg[rs]);
} void update(int l , int r , int k , int x , int v)
int mid = (l + r) >> 1;
if (x <= mid) update(l , mid , ls , x , v);
else update(mid + 1 , r , rs , x , v);
seg[k] = max(seg[ls] , seg[rs]);
}int query(int l , int r , int k , int tl , int tr)
int main()
build(1 , n , 1);
for(register int i = n; i; i--)
build(1 , n , 1);
for(register int i = 1; i <= n; i++) update(1 , n , 1 , a[i] , g[i]);
int ans = 0;
for(register int i = 1; i <= n; i++)
ans = max(ans , query(1 , n , 1 , 1 , a[i] - 1) + f[i]);
printf("%d" , ans);
}
數論 雙端佇列xLIS問題
對於數列中的某個點 求從它開始下降的最長子序列,這個序列將倒過來接到某點前面,成為最終的序列的前半段 求從它開始上公升的最長子序列,這個序列將倒過來接到某點後面,成為最終的序列的後半段 最終答案為某個點兩種子串行長度的和再減去1 因為統計了兩次自己 其餘的操作其實都可以省略。無法更優 include...
2020多校聯考 雙端佇列xLIS問題
觀察將乙個序列按一定方法加入到雙端佇列的性質。發現若直接在隊尾加入,則不會改變相對順序,而加入到隊頭的元素實際上是原序列的某個子串行再反過來。乾脆直接將原序列複製乙份到前面再反轉。那麼答案就是這個新序列的最長上公升子串行 考慮反轉過去後,前後對應相等的兩個元素不會同時出現在最長上公升序列中 用樹狀陣...
雙端佇列xLIS問題 棧 最長不下降序列
解題思路 通過推算可以發現,對於原數列的第i ii個數,一定是放在雙端佇列的中間,雙端佇列的左邊和右邊都為不下降序列 自動排除與答案無關的數 並且左邊和右邊的數在原數列中,都位於i的右邊 再加上雙端佇列插入元素的規律,又可以神奇地發現,雙端佇列右邊的數在原數列中的排列一樣,而左邊的數在原數列中是倒過...