【CF 1195】Basketball Exercise/Submarine in the Rybinsk Sea (hard edition)/OpenStreetMap+二维单调队列滑动窗口模板
寡人認為C,E都是比較板的題
butD2也太ex了,大大是被那個mod精給弄瘋了,我mod了那么多次還是炸了longlong orz
文章目錄
- 二維單調隊列模板
- C:Basketball Exercise
- 題目大意
- 題解
- 代碼實現
- D2:Submarine in the Rybinsk Sea (hard edition)
- 題目大意
- 題解
- 代碼實現
- E:OpenStreetMap
- 題目大意
- 題解
- 代碼實現
二維單調隊列模板
E題是一個二維單調隊列的板題,這里就先把板子甩出來
二維板子就是先維護每行,每行都是一個單調隊列,然后再用行去維護列
求n*m矩陣中,邊長為k的每個矩陣的最大值:
維護的行的最大值模板:
維護列的最大值的模板
void solve_col () {for ( int j = 1;j <= m;j ++ ) {int head = 1, tail = 0;for ( int i = 1;i <= n + 1;i ++ ) {if ( i >= k + 1 ) {while ( head <= tail && deq[head] < i - k )head ++;colmax[i][j] = rowmax[deq[head]][j];}while ( head <= tail && rowmax[deq[tail]][j] <= rowmax[i][j] )tail --;deq[++ tail] = i;}} }輸出模板:
for ( int i = 1;i <= n - k + 1;i ++ ) {for ( int j = 1;j <= m - k + 1;j ++ )printf ( "%d ", colmax[i][j] );printf ( "\n" ); }維護行的最小值的模板
void solve_row () {for ( int i = 1;i <= n;i ++ ) {int head = 1, tail = 0;for ( int j = 1;j <= m + 1;j ++ ) {if ( j >= k + 1 ) {while ( head <= tail && deq[head] < j - k )head ++;rowmin[i][j - k] = h[i][deq[head]];}while ( head <= tail && h[i][deq[tail]] >= h[i][j] )tail --;deq[++ tail] = j;}} }維護列的最小值的模板
void solve_col () {for ( int j = 1;j <= m;j ++ ) {int head = 1, tail = 0;for ( int i = 1;i <= n + 1;i ++ ) {if ( i >= k + 1 ) {while ( head <= tail && deq[head] < i - k )head ++;colmin[i][j] = rowmin[deq[head]][j];}while ( head <= tail && rowmin[deq[tail]][j] >= rowmin[i][j] )tail --;deq[++ tail] = i;}} }輸出模板
for ( int i = 1;i <= n - k + 1;i ++ ) {for ( int j = 1;j <= m - k + 1;j ++ )printf ( "%d ", colmin[i][j] );printf ( "\n" ); }六神裝已經出完,開始我們的三殺之旅吧!我要carry全場!
C:Basketball Exercise
題目大意
輸入n接下來輸入兩個長度為n的h1,h2序列
然后開始從1~n進行選取,當在i位置的時候
1)不選,跳過
2)如果上一次的選擇是h1數組,這一次就只能選h2[i]
3)如果上一次選的是h2序列,這一次就只能選h1[i]
求最后選取的數的和的最大值
n (1≤n≤10^5)
(1≤h2i,h1i≤10^9)
【輸入輸出樣例】
Input
5
9 3 5 7 3
5 8 1 4 5
Output
29
Input
3
1 2 9
10 1 1
Output
19
Input
1
7
4
Output
7
【樣例解釋】
灰色是選的點
樣例1:
樣例2:
題解
i點有三種情況,不選,或根據前一個操作決定是選h1還是h2
那么i與前面掛鉤,肯定可以搜索,數據范圍又大,搜索會炸
坑定就是dp啦,況且本仙女最差的就是dp這玩意,我都能一眼看出這是dp
你說這道題板不版!
dp式也很簡單我們定義一個二維就行,第一維表示模擬序列中i的位置,第二維三種狀態
0表示不選i,1表示上一次選的h2,2表示上一次選的h1
好了,上馬
代碼實現
#include <cstdio> #include <iostream> using namespace std; #define MAXN 100005 #define LL long long int n; int a[MAXN], b[MAXN]; LL dp[MAXN][3]; LL result; int main() {scanf ( "%d", &n );for ( int i = 1;i <= n;i ++ )scanf ( "%d", &a[i] );for ( int i = 1;i <= n;i ++ )scanf ( "%d", &b[i] );for ( int i = 1;i <= n;i ++ ) {dp[i][0] = max ( dp[i - 1][1], dp[i - 1][2] );dp[i][1] = max ( dp[i - 1][0], dp[i - 1][2] ) + a[i];dp[i][2] = max ( dp[i - 1][0], dp[i - 1][1] ) + b[i];}printf ( "%lld", max ( dp[n][1], dp[n][2] ) );return 0; }D2:Submarine in the Rybinsk Sea (hard edition)
ex至極,這tmd的mod就這么喜歡我嗎,我這幾天已經被它搞了3次了
你成全我吧!我們之間是沒有結果的,你是單箭頭,我已經把心交給了學習!
題目大意
輸入n然后n個數,每兩個數進行組合成一個新的數
如果第一個數位數大于第二個數的位數,第一個位數的前面不動,然后第一個數選一個,第二個數選一個。eg:91234,567,那么它們進行匹配的結果就是91253647
如果第二個數位大于第一個的數位,第二個位數的前面不動,還是第一個數選一個,第二個數選一個。eg:7658,123490,那么它們進行組合的結果就是1273645980
而且每兩個數能組合成兩個新數,因為這兩個數都可以分別成為第一個數
eg:1234,5678組合的新數分別是15263748和51627384
他也可以和自己組合,eg:23它與自己組合就是2233,不過這個數只統計一次
而如果是不同的i,j但是他們都是23,2233就要算兩次
求最后組合的所有新數的和取模998244353
n (1≤n≤100000)(1≤ai≤10^9)
題解
首先要知道兩個ai如果都是1e9就必須要開longlong
接著我們來思考如果i的位數小于等于j的位數
那么i對i,j進行組合后的新數的貢獻是一定的
eg:23,156組合后:12536,15263
23的個位對這些新數的貢獻和為3在十位和個位的和,即33
23的十位對這些新數的貢獻和為2在百位和千位的和,即2200
總貢獻就是2233
如果i的位數大于j的位數
就用上面的例子來說明
156的個位和十位算法與上面一致
而從它多的位數開始的時候,它在新數的位置是固定的
不過有兩個新數,那么156的百位的貢獻就是兩個10000,即20000
接下來用這種公式,就算位數為j的數字個數>2,直接乘以tot個數就行了
一定要注意mod,多mod又不會出事反正沒有除法是吧!模模益善!
終于可以上車了!把車門給我焊死
代碼實現
我寫得有點多,mod模的很多,主要是害怕炸longlong,結果后面還是炸到了cs
如果是位數大于等于a[i]
cs就是模擬的a[i]的第j位會對答案做出哪兩位的貢獻,比如模擬的是個位那么我就用cs算出他在十位和個位的總貢獻
如果是位數小于a[i]
cs還可以模擬固定的j位,比如23和145,cs就能模擬出1的貢獻是200
E:OpenStreetMap
題目大意
輸入n,m,a,b
再輸入g0,x,y,z
g[i]=(g[i?1] ? x + y) mod z
hi,j=g[(i?1)?m+j?1]
求在行n列m的h矩陣中,所有a*b矩陣中最小值的和
(1≤n,m≤3000, 1≤a≤n, 1≤b≤m)(0≤g0,x,y<z≤10^9)
題解
所有a*b矩陣就很像一個滑動窗口再加上是求最值,那坑定就是用單調隊列來維護
不過是個二維的滑動窗口罷了。。。我沒有想說的了
在代碼中我沒有用c數組來記錄維護的列的最小值,因為就多這一個二維數組,我就MLE
所以我在維護列的時候就順便吧答案也給求了!
話不多說,屁不多放,上馬
代碼實現
#include <cstdio> #include <iostream> using namespace std; #define LL long long #define MAXN 3005 LL n, m, a, b, ii, x, y, z; LL sum; LL g[MAXN * MAXN], h[MAXN][MAXN]; LL row[MAXN][MAXN]; LL deq[MAXN];void init () {g[0] = ii;for ( int i = 1;i <= ( n - 1 ) * m + m - 1;i ++ )g[i] = ( g[i - 1] * x + y ) % z;for ( int i = 1;i <= n;i ++ )for ( int j = 1;j <= m;j ++ )h[i][j] = g[( i - 1 ) * m + j - 1]; }void solve_row () {for ( int i = 1;i <= n;i ++ ) {int head = 1, tail = 0;for ( int j = 1;j <= m + 1;j ++ ) {if ( j >= b + 1 ) {while ( head <= tail && deq[head] < j - b )head ++;row[i][j - b] = h[i][deq[head]];}while ( head <= tail && h[i][deq[tail]] >= h[i][j] )tail --;deq[++ tail] = j;}} } void solve_col () {for ( int j = 1;j <= m;j ++ ) {int head = 1, tail = 0;for ( int i = 1;i <= n + 1;i ++ ) {if ( i >= a + 1 ) {while ( head <= tail && deq[head] < i - a )head ++;sum += row[deq[head]][j];}while ( head <= tail && row[deq[tail]][j] >= row[i][j] )tail --;deq[++ tail] = i;}} }int main() {scanf ( "%lld %lld %lld %lld", &n, &m, &a, &b );scanf ( "%lld %lld %lld %lld", &ii, &x, &y, &z );init ();solve_row ();solve_col ();printf ( "%lld", sum );return 0; }又到了說再見的時候,有任何問題的都可以留言,朕微服私巡的時候會回復的,不要太想大大哦~~
總結
以上是生活随笔為你收集整理的【CF 1195】Basketball Exercise/Submarine in the Rybinsk Sea (hard edition)/OpenStreetMap+二维单调队列滑动窗口模板的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ios7.0.6完美越狱百度输入法安装教
- 下一篇: 恐怖庄园的秘密攻略,游戏通关图文教程