在遊戲 Hoof Paper Scissors 中,Bessie 與 Elsie 各自從 個不同的手勢(蹄式)中選一個(編號為 到 ),並根據一張規則表,不同手勢間比賽時會有兩種結果:
而在 Hoof Paper Scissors Minus One 中,兩隻牛各自同時出示兩個手勢(左蹄一個、右蹄一個)。各自手勢都被對方看見後,他們再從自己的兩個手勢中選一個作為正式比賽所出的手勢,最後依照規則表決定勝負。
給定 Elsie 在每場比賽中預計要出的手勢組合(共 場比賽),Bessie 想知道自己有多少種手勢組合可以保證一定能贏過 Elsie。這裡「手勢組合」指的是一個有序對 ,其中 為左蹄的手勢, 為右蹄的手勢。
第一行包含兩個空格分隔的整數:
接下來 行:
接下來 行:
輸出 行,每行包含一個整數代表在第 場比賽 Bessie 有幾種手勢組合可以保證一定贏過 Elsie。
測資 2~6:
測資 7~12:無額外限制
此題用到了 AA 競程 Level 1 的「競程數學」中的知識點。
假設 Bessie 出的左蹄和右蹄手勢編號分別為 和 ,那麼 Bessie 一定能贏的情況就是 同時贏過 和 或 同時贏過 和 ,用 C++ 的程式語法來寫就是:
暴力枚舉 和 即可通過前 6 筆測資。
若要通過所有測資就要用點數學方法來計算 Bessie 一定能贏的組合數量。
首先,我們還是要先暴力計算有多少手勢是能同時贏過 和 的,令此數量為 。
接著 Bessie 能贏的數量其實就是「全部可能的手勢組合數量」減去「不能贏的組合數量」
「全部的組合數量」可用乘法原理算出是 ,而不能贏的組合數量就是 和 都不是那 個能贏的手勢的組合,也能利用乘法原理算出此數樣為 ,所以答案就是
今天牛群特別頑皮! Farmer John(FJ)只想拍下排成一行的牛,但牠們總在快要拍照時移動。
具體來說,FJ 有 隻牛 (),每隻牛都有一個介於 到 的整數高度。FJ 希望拍出一張牛的排列照片,要求牛的高度從左到右必須滿足以下三個條件:
FJ 可以移除部分牛,並重新排列剩下的牛。請求出 FJ 能夠在照片中包含的牛的最大數量,使得上述條件均被滿足。
輸入包含多個測試案例。
保證所有測試案例中 的總和不超過 。
輸出 行,每一行輸出一個整數,表示對應測試案例中 FJ 能在照片中包含的牛的最大數量。
此題的參考做法用到了 AA 競程 Level 0 競程入門班的「用陣列紀錄資訊」單元以及 Level 1 的「簡易貪心」單元中的知識點。
先最高的牛的高度,以及用陣列把每個高度的牛各有幾隻算出來。
由於牛的排列必須是「山形排列」,且相鄰的兩隻牛又不能一樣,那把牛的身高列出來可能會是如下:
1 2 4 7 9 7 4 2 1
可發現除了最大的數字外,其他數字都是恰出現兩次。
既然我們要找的是最長的排列,那麼我們讓身高最大的牛站在正中央一定能找到解,令身高最大的牛高度為 ,那麼對於所有 ,只要身高 的牛出現兩隻以上,我們就一定可以選其中兩隻出現在照片中,所以答案就是:
其中 代表身高為 的牛有幾隻, 為 艾佛森括號
Elsie 正試圖向 Bessie 描述她最喜愛的 USACO 競賽,但 Bessie 卻無法理解 Elsie 為何如此喜歡這個比賽。Elsie 說:「而且到了 mooin' time!誰想要來個 mooin'? 拜託,我只想參加 USACO。」
Bessie 仍然不懂,所以她將 Elsie 的描述記錄成一個長度為 () 的字串,字串由小寫英文字母組成,記作 。Elsie 定義一個由三個字元組成的字串 為 moo,當且僅當 且 。
一個三元組 若滿足 且字串 構成一個 moo,則稱該三元組有效。對於一個有效三元組,FJ 會進行以下操作以計算其值:
換句話說,三元組的值為 。
Bessie 向你提出 () 個查詢。在每個查詢中,她給出兩個整數 與 (, 且 ),要求你求出所有滿足 且 的有效三元組 中,其值的最大值。如果不存在任何有效三元組,請輸出 。
注意: 此題中涉及到的整數數值可能非常大,因此在程式中可能需要使用 64 位整數型態(例如 C/C++ 中的 "long long")。
對每個查詢,輸出一行答案,即該查詢中最大有效三元組的值;若不存在有效三元組,輸出 。
此題的參考做法用到了 AA 競程 Level 1「簡易貪心」、「數列相關函式」單元以及 「Level 1 公開課」中的知識點。
首先對於每個詢問我們要枚舉三元組的第二第三個元素是哪個字元,只有 種可能,每種可能各自算出最佳解後,再取最大的那個就是答案了。
接下來我們假設第二第三個元素對應的字母是 。
首先我們可以用貪心的概念來縮小我們要考慮的三元組的數量,最後可發現對於每個 ,其實我們至多只要考慮 個三元組,解説如下:
而 的位置可讀入字串後,就先預處理 陣列, 代表位置 右邊第一個和 不一樣的字母位置, 陣列求法請參考範例程式碼。
如此一來,對於如果 不是 ,那麼 就是 ,否則 就是 。
而 的求法可是先把所有字元 的位置放入一個 vector 裡,然後使用 來求。
最後,靠近 的位置也可使用 函式來求出,於是此題的時間複雜度分析如下:
給你兩個正整數 (),請構造一個非負整數數列 滿足以下條件:
此題的參考做法免強算是用到了 AA 競程 Level 1「簡易貪心」吧…
這種莫名其妙的構造題,感覺就是用來防 chatGPT 用的 XD
題目只有兩個參數 和 ,不妨先固定其中一個參數,想想看另一個參數在什麼時候會有解,尤其時去思考看看有解時該參數的極小極大值會是什麼
例如我們可以固定 ,思考看看對於同一個 值, 最小能多小。
由於 是所有 位元 的數量 xor 起來的結果,那也就是說,如果 二進制最高位是 ,那麼無論如何都至少要有一個 含有的 位元 的數量是 以上了。
這樣想下去大概能發現 最小的情況會發生在 所有的 都是 的冪次方,且 的時候,於是我們就能夠貪心地算出給定 時, 的可能最小值,令此值為 。
接著分 種情況討論。
當 ,無解。
當 ,且 是偶數時,我們就只要先把輸入為 f(K) K
的解構造出來,最後數列 再加上兩個 就是答案了。
當 ,且 時,又有兩種情況:
f(K) K
的解有某個 ,那把此 改成 ,此 的位元 數量不會改變,但 的總和增加 了,所以也會是現在的輸入的解。f(K) K
的解不存在任何一個 ,那麼就無解,因為要讓題目要求的第三個條件不變的情況,並要把 的總和變大,增加的量不可能只有 。當 ,且 是 的奇數時,首先先把輸入為 f(K) K
的解構造出來,然後發現 再增加 這兩個數字後,題目要求的第三個條件的 xor 結果也不會改變,但 的數字和增加了 ,接著,若要再讓 的總和增加某個 ( 是偶數),就只要把數列 的再加入 個 即可。
有非常多隻牛,每個牛都有一個數字代表他的 ID,但有可能有一些牛共用同個 ID。給你正整數 ,代表共有 種不同的 ID,第 種 ID 對應的數字是 ,並且有 隻牛的 ID 是 ()。
給你兩個數字 (),兩隻牛若他們的 ID 加起來為 或 的話,這兩隻牛就可以湊成一對,每隻牛至多只能和其他一隻牛湊成一對,請問所有牛至多可湊成幾對?
此題的參考做法用到了 AA 競程 Level 1「簡易貪心」和「關聯容器」單元裡的知識點
可把每個 ID 都視為圖論上的點,若兩個相異的 ID 可以配對就連一條邊,若一個 ID 自己和自己能配對,就把該點視為「特殊的點」。可發現此圖的每個點度數至多只有 ,且不會有環,也就是說此圖是由很多條鏈(整個連通塊本身就是一條路徑(path) 的子圖)構成。
每條鏈之間是互相不影響的,所以可分開考慮,算出各條鏈的答案再加總起來即可。
對於一條鏈,至少會有一個度數為 的端點不是「特殊的點」,可發現優先把此點對應的 ID 的牛和他們唯一能配對 ID 的牛配對一定不會比較差,配完後,就可把此點移除,接下來一直做一樣的事,直到最後只剩下特殊的點,再把特殊的點對答案的貢獻算上即可。
存在各式各樣的實作方式,範例程式碼用 dfs 的概念實作。
Bessie 與她的朋友們準備去滑雪旅行。這座山上有 個「中繼點」(waypoints),分別標記為 ,海拔依照編號遞增(其中中繼點 在山底)。
對於每個中繼點 ,都有一條滑雪道從 處開始,一直延伸到 () 處。每條滑雪道各自有一個「難度」(difficulty) 與「樂趣」(enjoyment) ,其中
Bessie 有 位朋友(),他們將依照以下方式滑雪:
對於滑過的每一條滑雪道,朋友所獲得的「樂趣」會累加;整段旅程的總樂趣即為沿途所有滑雪道的樂趣總和。
不過,每位朋友也有自己不同的「技能值」(skill) 與「勇氣值」(courage) ,範圍為:
第 位朋友只能選擇路徑上難度超過 的滑雪道至多只有 條的路徑。
你的任務是:對於每位朋友,計算他能獲得的最大樂趣總和。
long long
)以避免溢位。此題的參考做法用到了 AA 競程 Level 2「深度優先搜索(DFS)」和 Level 1「關聯容器」單元裡的知識點,並假設大家已有 DFS 的 backtracking(回溯法) 的概念
首先注意到一個重點:
若第 位朋友可以從中繼點 出發,代表著:「該條路徑難度第 大(從 開始編號) 的滑雪道值小於等於 。」
於是若不管時間複雜度,我們可以有個 的做法如下:
每個朋友的答案各自計算,再枚舉所有中繼點 i 作為起點的情況,搜集該路徑所有滑雪道難度,求出第 c_i + 1 大的難度值,若該值 <= s_i,那麼此路徑的「樂趣」總和就能更新此位朋友的答案
接著我們來一步一步優化此做法。
1. 利用DFS+回溯的概念優化
上述比較暴力的做法是每個朋友都要獨立計算一次,但每次計算都要重新算一次每條路徑第 大的困難度,況且 的值其實只有 種,若可以一剛開始就算出來,那對時間複雜度優化肯定是有幫助的。
這部分我們可使用 DFS+回溯的概念,改成從 號中繼點當起點 DFS,並在全域維護一個 multiset,儲存 DFS 時起點到當前點路徑上所有滑雪道的難度,這樣 DFS 時每走到一個中繼點 ,就能求出 好中繼點到 號中繼點的路徑中前 大困難度的值了。這部分總時間複雜度只要 (此時間複雜度的計算是把 當常數)
**2. 把資料整理成單調序列,以便利用 upper_bound 優化
接著,對於相同 值,我們回溯後可以得到許多個 pair ,代表若第 位朋友的技能值() 大於等於 ,就可以有總和為 的「樂趣」,若存在兩個 pair 和 ,若 但 ,那麼 至個 pair 就不需要考慮了,因為他不會比 還好。於是我們可先把所有 pair 按照 值排序,排完後,再把剛才說不需要考慮的那些 pair 移除,剩下的 pair 就會隨著 的遞增, 也是遞增的。於是對於每個詢問,我們就可以使用 upper_bound 找到 的最大的 的 pair,此 pair 的 值就是該詢問的答案。
輸入給你三個正整數 (),以及給你一個長度為 且由英文大寫字母 'M'
和 'O'
組成字串 ,而你要處理的真正字串是由 複製 次接起來的字串。例如說,當 $s = $ "MOMOOO"
,,那麼你要處理的真正字串是:"MOMOOOMOMOOOMOMOOO"
。
定義 字串是由一個 'M'
後面接上 個 'O'
形成的字串。
現在請你回答以下問題:
要把 複製 次接起來的字串拆成很多個子序列,使得每個子序列都是長度為 字串,請問有幾種拆法?(保證至少有 種拆法) 請輸出答案除以 的餘數。
例如,當 且 "MOMOOO"
,就有 種拆法:
此題的參考做法用到了 AA 競程 Level 4「特殊 DP 題型」裡所介紹的組合數相關知識。
看完這道題我第一個想法是:「這道題放在金組也太簡單了吧…」
首先,由於題目保證至少有一種拆法,所以字串 裡 'O'
的數量一定是 'M'
的 倍,接著 這個參數對此題難度的影響非常少,因為可發線每個子序列一定是在同一份複製出來的 裡,所以 複製 次的答案其實就是只有一個 的答案的 次方。
最後來解說要怎麼計算當 時的答案。
我們只要從右往左枚舉字串裡的每個字元,並用一個變數 紀錄目前有多少個被枚舉到的字母 'O'
還沒被確定是放在哪個子序列裡,而當我們枚舉到 'O'
時 就增加 ;而當枚舉到 'M'
時,我們就決定這個 'M'
後面要接哪些字母 'O'
,因為還有 個字母 'O'
還沒決定要放在哪個子序列,所以我們就有 種選擇方式,可直接把此值乘上答案後,在把 的值減少 即可。時間複雜度為 。
給你一個長度為 的數列,,接下來有 次詢問,每次詢問都會給你兩個正整數 代表你要把 的值改為 ,請你回答以下問題:
請把數列 拆成兩個非空的子序列,使得此兩子序列的眾數的差的絕對值盡可能大(如果眾數有很多個,可以任取一個)。舉例來說,數列
此題的參考做法用到了 AA 競程 Level 5「根號資料結構與演算法」單元的知識點
先提一下,我覺得出題者使用的方法極可能和我的方法不一樣,這種複雜的資料結構題通常都有好多種做法。
定義 代表數字 在 裡出現幾次。
先介紹 4 個觀察:
有了第 個觀察後,如果我們有辦法每個詢問都只花 的時間把這 個要考慮的數字找出來,那麼此題就可以用 的時間解決啦!
而要找到這些要考慮的數字,其實只要找到所有非空的 的索引值即可。
至於這件事我們要用根號分塊來解決。
在程式碼裡,我們會真的使用 STL 的 set 表示觀察 3 裡的 (程式碼裡叫做 ),可以發現,每個詢問裡只會改變兩個數字的數量,也就是至多會變動到 個 。
有了這樣的觀察後其實就有很多種解決方式了,這裡只介紹我程式碼使用的方法:
把集合 每 個一組,並用集合 儲存第 組中非公的 的索引值。
每個詢問都變動到的 至多只會出現在 組裡,再用 的時間暴力更新這幾組的 ,更新完後,在用 的時間把所有集合 裡的索引值按照小到大搜集起來即可。
細節請直接參考程式碼。
有一個長度為 的數列 (),Bessie 和 Elsie 根據此數列完以下遊戲:
假設 Bessie 和 Elsie 都採取最佳策略,請問遊戲最終分數會是多少?
此題的參考做法用到了 AA 競程 Level 2「二分搜常見題型」單元的知識點
首先,可用貪心的思維證明在最佳策略中, Bessie 一定是選 中最大的 個數增加 ,而 Elsie 也會是選 中最大的 個數減 ,就結論而言,每一輪操作會是數列 中第 大的數至第 大的數都增加 。
那麼除了最大的 個數以外的數肯定是維持不變的,就先把他們忽略,最終答案再加上這些數的平方和,所以我們就直接當作數列 長度為 ,每次操作則是會把數列裡最小的 個數增加 。
但這題困難的點在於回合數實在太多了,那該怎麼辦呢?
(以下已經把數列 m 的長度視為 A 了)
模擬一些 case 後可發現,由於我們一定是盡可能讓比較小的數變大,最終數列 的長相一定是存在某個數字 ,原本數列 裡小於等於 的 都會變為 ,或是變為 (一定變為這樣的證明請參考 CF1551 B2. Wonderful Coloring - 2 的題解,其實和這題 Codeforces 題是樣的東西),那我們就去二分搜這個 值即可,也就是說,要找到最大的 ,使得 ,二分搜求出 值之後,就不難得到數列 的最終長相,然後就可以算出最終得分。