日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【CF 1195】Basketball Exercise/Submarine in the Rybinsk Sea (hard edition)/OpenStreetMap+二维单调队列滑动窗口模板

發布時間:2023/12/3 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【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_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 ++;rowmax[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 ++;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

#include <cstdio> #define LL long long #define mod 998244353 #define MAXN 100005 LL n; LL a[MAXN]; LL tot[MAXN]; LL wei[MAXN]; LL result; int main() {scanf ( "%lld", &n );for ( int i = 1;i <= n;i ++ ) {scanf ( "%lld", &a[i] );LL tmp = a[i];int cnt = 0;while ( tmp ) {cnt ++;tmp /= 10;}wei[i] = cnt;tot[cnt] ++;}for ( int i = 1;i <= n;i ++ ) {for ( int j = 1;j < wei[i];j ++ ) {if ( tot[j] == 0 ) continue;LL x = a[i], cs = 1, many = 1, t;while ( x ) {cs %= mod;t = x % 10;if ( many <= j ) result = ( result + ( t * cs % mod + cs * 10 % mod * t % mod ) % mod * tot[j] % mod ) % mod;elseresult = ( result + tot[j] * 2 % mod * t % mod * cs % mod ) % mod;x /= 10;if ( many <= j ) cs *= 100;else cs *= 10; many ++;}}for ( int j = wei[i];j <= 10;j ++ ) {if ( tot[j] == 0 ) continue;LL x = a[i], cs = 1, t;while ( x ) {cs %= mod;t = x % 10;result = ( result + ( t * cs % mod + cs * 10 % mod * t % mod ) % mod * tot[j] % mod ) % mod;x /= 10;cs *= 100;}}}printf ( "%lld", result % mod );return 0; }

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+二维单调队列滑动窗口模板的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。