雅禮集訓 2018 Day10 貪玩藍月

2022-06-04 11:03:08 字數 1738 閱讀 9447

點這裡看題目。

離線的話,我們顯然可以 線段樹分治 + dp ,時間複雜度大概是 \(o(m\log_2m+mp)\) 。

顯然我們需要乙個 dp 去維護答案,這裡不再贅述。

考慮我們直接處理的難點之一是雙端佇列兩段可操作,而一端可操作的結構,棧,就可以簡單地維護 dp 。因此,我們考慮將雙端佇列拆成兩棧分別維護左端和右端

有了這個思路,剩下的都比較簡單了。插入操作可以直接維護 dp 陣列。刪除操作可以把棧頂的 dp 陣列清空。查詢的時候,我們列舉一端的 dp 值 \(dpl(i)\) ,此時對應可用的 \(dpr\) 的值必然是一段區間,我們可以考慮使用單調佇列之類的資料結構維護一下。

插入、查詢都可以做到 \(o(p)\) 。刪除時,如果一端的棧已經被刪空了,我們需要在另一端的棧裡打上標記,在之後對兩個棧進行均分重構

時間複雜度是 ...... \(o(?\times p)\) 。

#include #include typedef long long ll;

const ll inf = 1e10;

const int maxn = 5e4 + 5, maxp = 505;

templatevoid read( _t &x )

while( s >= '0' && s <= '9' )

x *= f;

}templatevoid write( _t x )

if( 9 < x )

putchar( x % 10 + '0' );

}template_t max( const _t a, const _t b )

ll dpl[maxn][maxp], dpr[maxn][maxp];

ll f[maxp << 1];

int q[maxp];

int stkl[maxn], stkr[maxn];

int tmp[maxn];

int w[maxn], v[maxn];

int n, p, topl, topr, butl, butr;

void rebuild();

void upt( ll &x, const ll v )

int fix( const int a )

void popl()

topl --;

if( ! topl ) rebuild();

}void popr()

topr --;

if( ! topr ) rebuild();

}void insertl( const int id )

void insertr( const int id )

void rebuild()

ll query()

while( h <= t && q[h] < l - i ) h ++;

ans = max( ans, f[q[h]] + dpl[topl][i] );

} r = 0;

for( int i = p - 1 ; i > l ; i -- )

while( h <= t && q[h] < l - i + p ) h ++;

ans = max( ans, f[q[h]] + dpl[topl][i] );

}return ans < 0 ? -1 : ans;

}int main()

return 0;

}

雅禮集訓 2018 Day4 Magic

傳送門本部分 於 這位大佬 題中要求本質不同的序列數量,不太好搞。我們考慮給相同顏色的牌加上編號,這樣所有牌都不相同。那麼如果我們求出了答案,只需要將答案除以 prod a i 就好了。恰好有 k 對 不能直接求,考慮容斥,如果我們求出了 g x 表示至少有 x 對的方案數,那麼答案即為 sum l...

雅禮集訓 2018 Day7 A 題解

題意 雅禮集訓 2018 day7 a 題解 線段樹處理。考慮只有一種與的操作。顯然當乙個區間的或和與上將要與的數還是原數時就沒必要遞迴計算了,剪枝剪掉。當一段區間與和與上將要與的數等於這段區間或和與上將要與的數時,更新後這段區間的最小值位置還是更新前的位置。由於一次操作至少將數的乙個二進位制改變,...

雅禮集訓Day4

今天炸的1p。t1,給你100次詢問,每次l,r,選 l,r 中的若干數進行異或,求有多少種結果,1 l r 1e18.做法 暴力很顯然是將l,r這些數加入線性基,然後算一下線性基里有多少個數。我們可以考慮線性基的每一位最早在多久被加入。這個就可以看l了,它二進位制的最高位很顯然是一開始就加入線性基...