Certified Software Professional - Senior 非專業級軟體能力認證測試
本解析不提供閱讀程式與完善程式題目的程式碼,如有需要請透過 luogu.com.cn 相關連結 下載
如有謬誤煩請指正
答案
AACBB
BDABD
ACBCD
✓××BC
✓✓✓BCC
✓×✓CAC
AAAAA
AABAA
單項選擇
1
在 Linux 系統中,如果你想顯示當前工作目錄的路徑,應該使用哪個命令?
A
pwd
Bcd
Cls
Decho
pwd
: print working directory
cd
: 跳轉到指定目錄
ls
: 列出當前目錄的所有子檔案和子資料夾
echo
: 輸出指定內容
2
假設一個長度為n的整數陣列中每個元索值互不相同,且這個陣列是無序的。要找到這個陣列中最大元素的時間複雜度是多少?
A \(O(n)\)
B \(O(logn)\)
C \(O(nlogn)\)
D \(O(1)\)
無序的陣列只能透過兩兩比較來查詢,需要比較 \(n-1\) 次(第一次不需要比較),因此為 \(O(n)\)
3
在 C++中,以下哪個函式呼叫會造成溢位?
A
int foo(){ return 0;}
Bint bar(){int x=1;return x; }
Cvoid baz(){ int a[1000];baz();)
Dvoid qux(){ return; }
函式棧溢位一般有兩種:函式內變數開的太大,或者函式遞迴深度太深
這裡 baz()
函式重複呼叫自身,無終止條件,因此會溢位
4
在一場比賽中,有 \(10\) 名選手參加,前三名將獲得金、銀、牌。若不允許並列,且每名選手只能獲得一枚獎牌,則不同的頒獎方式有多少種?
A 120
B 720
C 504
D 1000
不妨選出一個長度為 \(3\) 的序列,依次獲得金,銀,銅牌,則方案有 \(A^{3}_{10}=10\times 9\times 8=720\) 種
5
下面哪個資料結構最適合實現先進先出(FIFO)的功能?
A 棧
B 佇列
C 線性表
D 二叉搜尋樹
棧是先進後出
後面兩種資料結構不具備存放與彈出基本資料的功能
線性表在功能上類似陣列
6
已知 \(f(1)=1\),且對於 \(n\ge2\) 有 \(f(n)=f(n-1)+f(⌊n/2⌋)\) ,則 \(f(4)\) 的值為:
A \(4\)
B \(5\)
C \(6\)
D \(7\)
\(f(2)=f(1)+f(1)=2\)
\(f(3)=f(2)+f(1)=3\)
\(f(4)=f(3)+f(2)=5\)
7
假設有一個包含 \(n\) 個頂點的無向圖,且該圖是尤拉圖。以下關於該圖的描述中哪一項不一定正確?
A 所有頂點的度數均為偶數
B 該圖連通
C 該圖存在一個尤拉回路
D 該圖的邊數是奇數
尤拉圖定義:僅由尤拉回路構成的圖
尤拉回路:即一筆能畫完的圖。形式化地說,尤拉回路是從任意一個點出發,不重複經過任何一條邊,也不遺漏任何一條邊,最終仍能回到該節點的路徑
根據定義,D 是錯誤的,反例為一個正方形
8
對陣列進行二分查詢的過程中,以下哪個條件必須滿足?
A 陣列必須是有序的
B 陣列必須是無序的
C 陣列長度必須是 \(2\) 的冪
D 陣列中的元素必須為整數
二分查詢本質上也是一種二分答案,需要保證答案具有單調性
9
考慮一個自然數 \(n\) 以及一個數 \(m\),你需要計算 \(n\) 的逆元(即 \(n\) 在 \(m\) 意義下的乘法逆元),下列哪種演算法最為適合?
A 使用暴力法依次嘗試
B 使用擴充套件歐幾里得演算法
C 使用快速冪法
D 使用線性篩法
逆元的定義是這樣的:
定義 \(a\) 在模 \(p\) 意義下的逆元 \(b\) 滿足 \((\frac{c}{a})\mod p=(c\times b)\mod p\)
當 \(p\) 為質數的時候,才能使用快速冪(+費馬小定理)來求逆元,而擴充套件歐幾里得演算法為更加通用的求逆元方法,只需要滿足兩個數互質
更詳細的求逆元方法可以透過 這篇文章 的 5.3.1 章瞭解
10
在設計一個雜湊表時,為了減少衝突,需要使用適當的雜湊函效和衝突解決策略。已知某雜湊表中有 \(n\) 個鍵值對,表的裝載因子為 \(a(0<a\le 1)\) 。在使用開放地址法解決衝突的過程中,最壞情況下查詢一個元素的時間複雜度為
A \(O(1)\)
B \(O(logn)\)
C \(O(1/(1-a))\)
D \(O(n)\)
開放地址法解決衝突:假設當前元素 \(x\) 需要放入地址 \(p\) 中,但現在 \(p\) 位置已經有了元素,直接放置就會導致衝突,因此考慮向後依次找,找到第一個沒有放置元素的位置放置,這樣可以防止衝突(遍歷到最後再從頭開始)
因此最壞情況下需要把整個表遍歷一遍,複雜度為 \(O(n)\)
科普裝載因子的定義:裝載因子定義了一個閾值,當雜湊表中的條目數超出了載入因子與當前容量的乘積時,則要對該雜湊表進行擴容、rehash操作(即重建內部資料結構),擴容後的雜湊表將具有兩倍的原容量。
11
假設有一棵 \(h\) 層的完全二叉樹,該樹最多包含多少個結點?
A \(2^h-1\)
B \(2^{h+1}-1\)
C \(2^h\)
D \(2^{h+1}\)
因為每個節點都有兩個兒子,因此每一層的節點個數都是上一層的兩倍
總結點數為 \(1+2^{1}+2^{2}+\cdots+2^{h-1}=2^{h}-1\)
12
設有一個 \(10\) 個頂點的完全圖,每兩個頂點之間都有一條邊。有多少個長度為 \(4\) 的環?
A \(120\)
B \(210\)
C \(630\)
D \(5040\)
因為圖完全聯通,任取四個點一定能保證它們構成一個環
因為環上的點是無序的,因此很多人會考慮計算 \(C^{4}_{10}=\frac{10\times 9\times 8\times 7}{4\times 3\times 2\times 1}=210\),然而這樣是錯誤的
考慮是什麼地方出了問題
剛才我們說,任取四個點一定能保證它們構成一個環
但是環 1 2 3 4
和環 2 1 3 4
並不是同一個環,前者有 1->2->3
的連邊,後者有 2->1->3
的連邊,顯然不是同一個環
正確的做法是考慮重複的環:
注意到 1 2 3 4
2 3 4 1
3 4 1 2
4 1 2 3
是重複的,以此類推,每一種可能的組合都有四種可能的起始節點,因此會重複計算 \(4\) 次
另外,注意到 1 2 3 4
4 3 2 1
是重複的,同樣,上面的每一種反過來和原來都是一樣的,因此答案為 \(\frac{A^{4}_{10}}{2\times 4}=630\)
13
對於一個整數 \(n\)。定義 \(f(n)\) 為 \(n\) 的各位數字之和。問使 \(f(f(x))=10\) 的最小自然數 \(x\) 是多少?
A \(29\)
B \(199\)
C \(299\)
D \(399\)
代選項即可
\(f(29)=11,f(f(29))=2\)
\(f(199)=19,f(f(199))=10\)
\(f(299)=20,f(f(299))=2\)
\(f(399)=21,f(f(399))=3\)
14
設有一個長度為 \(n\) 的 01 字串,其中有 \(k\) 個 \(1\) ,每次操作可以交換相鄰兩個字元。在最壞情況下將這 \(k\) 個 \(1\) 移到字串最右邊所要的交換次數是多少?
A \(k\)
B \(\frac{k\times (k-1)}{2}\)
C \((n-k)\times k\)
D \(\frac{(2n-k-1)\times k}{2}\)
D 這個數的來源:令全部數字都排在最左邊,然後從右到左一個一個挪,然後認為答案是 \((n-1)+(n-2)+(n-3)\cdots+(n-k)\)
實際上,在排後面的數字時,由於右邊已經有排好的數字,不需要將新來的數字與排好的數字進行比較與交換了,所以每個數字的交換次數只有 \((n-k)\) 次,一共 \(k(n-k)\) 次
15
如圖是一張包含 \(7\) 個頂點的有向圖,如果要除其中一些邊,使得從節點 \(1\) 到節點 \(7\) 沒有可行路徑,且刪除的邊數最少,請問總共有多少種可行的刪除邊的集合?
A \(1\)
B \(2\)
C \(3\)
D \(4\)
一個可能更醜的圖
上來先注意到 \(\{8,9\}\) 是合法的,並且不存在只刪一個邊的解法,因此最優解為 \(2\)
可行的邊的集合
\(\{8,9\}\)
\(\{5,6\}\)
\(\{6,8\}\)
\(\{1,6\}\)
閱讀程式
1
分析
logic() 函式內的位運算,採用列舉法來判斷
- 當 \(x=0,y=0\) 時,
(0 & 0) ^ ((0 ^ 0) | (~0 & 0))
=0 ^ (0 | 0)
=0
- 當 \(x=0,y=1\) 時,
(0 & 1) ^ ((0 ^ 1) | (~0 & 1))
=0 ^ (1 | 1)
=1
- 當 \(x=1,y=0\) 時,
(1 & 0) ^ ((1 ^ 0) | (~1 & 0))
=0 ^ (1 | 0)
=1
- 當 \(x=1,y=1\) 時,
(1 & 1) ^ ((1 ^ 1) | (~1 & 1))
=1 ^ (0 | 0)
=1
因此為邏輯或運算
觀察到 recursion() 函式非常像快速排序演算法,但是有最大遞迴深度限制,最多隻會進行 depth
層遞迴,因此 這個排序演算法的結果不一定有序
因為快速排序最多隻會進行 \(\log n\) 層,因此當 \(d\ge \log b\) 時,輸出的序列是有序的
題目
- 當 \(1000\ge d\ge b\) 時,輸出的序列是有序的
\(d\ge b\ge \log b\),正確
- 當輸入
5 5 1
時,輸出為1 1 5 5 5
透過暴力模擬可以發現,初始陣列為 5 5 1 1 5
,排序函式只進行了一層,排序不完全,輸出值為 5 1 1 5 5
- 假設陣列
c
長度無限制,該程式所實現的演算法的時間複雜度是 \(O(b)\) 的
該排序演算法在每一層都花費 \(O(b)\) 遍歷了一遍陣列,然而該演算法共有 \(d\) 層,因此複雜度為 \(O(bd)\)
- 函式
int logic(int x,int y)
的功能是
按位或,詳見上方解析
- 當輸入為
10 100 100
時,輸出的第 \(100\) 個數為
\(d\ge \log b\),可知輸出陣列是有序的,也即讓我們求一個最大的數
嘗試代選項,判斷哪個數可以透過 \(0\) 到 \(99\) 內的數 \(i\) 透過 (a|i)%(b+1)
得到,可以發現 \(98\) 不合法(不存在 \(a\) 中為 \(1\) 的二進位制位),而 \(95\) 合法,因此為 \(95\)
詳細地說,二進位制意義下 a=1010
,而 98=1100010
,顯然,如果一個數為 a|i
的形式,那麼第四位一定是 \(1\),類似地,98+101=11000111
同樣不合法(需要考慮這個是因為 (98+101)%101=98
),因此 \(98\) 不合法
2
分析
觀察 solve() 函式的 dp 部分
發現 int k = (j<<1)|(s[i]-'0')
這一句,其實就相當於是在 \(j\) 的後面再拼一個數字,然後用拼接前的數字去更新拼接後的數字,因為拼接上的數字都是 s[i]
中的內容,i
為正序遍歷,初態為 \(0\),那麼我們發現,該 dp 陣列一直在嘗試將 s 中新的字元拼接到已有的字元後面,並且這樣的拼接是有序的,只能將後面的字元拼接到前面的字元後面,綜合這三個條件我們可以總結出:這個 dp 陣列是在統計 s
的子序列方案數
但是這個方案數是有限制的,下面我們對這些限制來進行一些描述
- 注意到只有在 \([0,2^{m-1}-1]\) 內的數字才能用於對答案進行更新,對應到二進位制就是所有不大於 \(m\) 位的二進位制數,因此,
s
中大於 \(m\) 位的子序列是不會被統計到的 - 此外的一個限制條件是
if(j !=0 || s[i]=='1')
,這是這個函式區別於 solve2() 的最大不同點,這意味著當一個子序列開頭是 \(0\) 的時候,由於j=0,k=0
,因此無法進行更新,也就是說 這個函式要求子序列的開頭必須是 \(1\)
隨後函式統計了所有 i*dp[i]
的值,值*方案數=總和
根據以上條件,我們可以總結出該函式的功能:找出 s 全部以 \(1\) 開頭的,不超過 \(m\) 位的子序列的十進位制值總和
下面來看 solve2(),它則列舉了全部 \([0,2^{n}-1]\) 的全部情況,轉為二進位制即為全部不超過 \(n\) 位的二進位制數,隨後,如果二進位制位為 \(1\),就把該位上的 s 拼接到已有的字元後面(num = num * 2 + (s[j]-'0')
一句),可以發現 solve2() 同樣是在找子序列的值,那麼我們來說一下 solve2() 的限制
- 注意到,雖然我們列舉了所有可能的情況,但只有
cnt<=m
的數才能對答案進行更新,也就是說最終子序列中最多隻能拼接 \(m\) 個數
也就是說這個函式的功能為:找出 s 全部不超過 \(m\) 位的子序列的十進位制值總和
可以發現,兩者的差距就在是否以 \(1\) 開頭
題目
- 假設陣列
dp
長度無限制,函式 solve() 所實現的演算法的時間複雜度是 \(O(n2^{m})\)
solve() 函式的核心演算法與複雜度瓶頸為兩層 for
迴圈,根據 solve() 函式的 for
迴圈邊界,可以得出其複雜度為 \(T(n2^{m-1})\),即 \(O(n2^{m})\)(相當於乘以一個常數 \(2\))
- 輸入
11 2 10000000001
時,程式輸出兩個數32
和23
對於 solve2()
\(m=1\) 時:11 個數,貢獻為 \(2\times 1+9\times 0=2\)
\(m=2\) 時:10
有 \(9\) 種,01
有 \(9\) 種,11
有 \(1\) 種,貢獻為 \(2\times 9+1\times 9+3=30\)
總貢獻 \(2+30=32\)
對於 solve()
\(m=1\) 時:11 個數,貢獻為 \(2\times 1+9\times 0=2\)
\(m=2\) 時:10
有 \(9\) 種,01
有 \(0\) 種(不合法),11
有 \(1\) 種,貢獻為 \(2\times 9+1\times 0+3=21\)
總貢獻 \(2+21=23\)
故正確,這道題最大的坑點就是實際輸出的時候 solve2() 在前
- 當 \(n\le 10\) 時,solve() 的返回值始終小於 \(4^{10}\)
可以發現其子序列貢獻最多為 \(\sum^{10}_{i=1}C^{i}_{10}\times (2^{i}-1)\) 個(這裡的做法不是本題所需要的,如果你想知道為什麼是這個式子,可以去下面 "當 \(n\le 6\) 時,solve() 的最大可能返回值為" 那道題去找)
但是考場上顯然我們不好算這麼大的數,因為我們找出的所有子序列都小於 \(1111111111\),而我們一共有 \(2^{10}\) 個數,而每個數都不會超過 \(2^{10}\),因此一定小於 \(2^{10}\times 2^{10}=2^{20}=4^{10}\),因此正確,這也是出題人把這個數設成 \(4^{10}\) 的意圖
- 當 \(n=10\) 且 \(m=10\) 時,有多少種輸入使得兩行的結果完全一致
根據剛才的分析,不能存在任何以 \(0\) 開頭,且有值的子序列,也就是說,只要序列中出現了 \(0\),必須保證後面的數都沒有值,即都是 \(0\)
不難發現 0000000000
,1000000000
,1100000000
,1110000000
,1111000000
,1111100000
,1111110000
,1111111000
,1111111100
,1111111110
,1111111111
都符合要求,共 \(11\) 種
- 當 \(n\le 6\) 時,solve() 的最大可能返回值為
考慮極限情況,即 \(111111\),且 \(m\ge n\),此時每一位對答案都會有最大貢獻,即答案也最大,那麼,位數為 \(1\) 的子序列共有 \(C^{1}_{6}\) 個,而因為每一位都為 \(1\),因此每一個的值都為 \(1\),同理,位數為 \(2\) 的子序列共有 \(C^{2}_{6}\) 個,每一個的值都為 \(3\),以此類推,可以發現其子序列貢獻最多為 \(\sum^{6}_{i=1}C^{i}_{6}\times (2^{i}-1)=665\) 個
- 若 \(n=8,m=8\),solve 和 solve2 的返回值最大可能的差值為
和上面那個結果完全一致的題正好反過來了,這道題裡我們需要一個以 \(0\) 開頭的子序列值最大的序列,那麼容易想到的是這個序列開頭一定是 \(0\),為了使後面的值最大,我們構造出 01111111
這樣的序列作為答案
題目讓我們計算的差值,實際上也就是以 \(0\) 開頭的子序列權值和,去掉開頭的 \(0\),也就相當於求 \(n=7,m=7\) 時 1111111
的子序列權值和,又回到剛才那個問題,答案為 \(\sum^{7}_{i=1}C^{i}_{7}\times (2^{i}-1)=2059\) 個
3
分析
首先來看 \(p\) 陣列,可以發現其用於埃氏篩(init() 函式內區域性程式碼),最後篩出來,\(p_{i}=1\) 則表示 \(i\) 為素數
然後觀察變數 const P1,P2,B1,B2,K1,K2
其中 P1,P2
用於取模,而後面這兩組變數,一組用於給 H
賦初值,另一組用來生成 p1,p2
陣列(在主函式中),發現其格式類似 線性同餘,判斷作用為生成隨機數,也就是說,p1,p2,H
三種變數的起始值均是隨機的,推測是雜湊演算法
對於這個雜湊結構體 H
,我們可以觀察出如下這幾點:
H
定義的加法不滿足交換律H
中有兩個雜湊引數h1,h2
,另外一個引數l
記錄合併的次數,同時也參與運算
下方的選擇題問我們,H
的合併方式看起來像什麼,後面列出的選項全都是樹上操作,據此推測該演算法是樹雜湊,一個節點的初值由該節點編號是否為質數來決定,一個節點最終的雜湊值由其初值,左子樹值,右子樹值共同決定,當兩個節點對應的子樹(這裡指子樹結構和子樹上節點的 p
陣列狀態)完全相同時,這兩個節點的雜湊值就相等
隨後程式進行了排序與去重,這並不在樹雜湊的演算法範圍內,用處在下方題目中會有體現
題目
- 假設程式執行前能自動將
maxn
改為n+1
,所實現的演算法的時間複雜度是 \(O(n\log n)\)
總複雜度為篩法+排序+去重= \(T(n\log\log n+n\log n+n)=O(n\log n)\)
- 時間複雜度的瓶頸在 init()
init(): \(T(n+n\log\log n)\)
solve(): \(T(2n+n\log n)\)
顯然 solve() 更大
- 若修改常數
B1
或K1
的值,該程式可能會輸出不同的結果
程式第一行輸出的是雜湊值,儘管修改雜湊內部的引數並不影響雜湊判等(不考慮雜湊衝突),但仍然會導致雜湊值改變,因此正確
- 在 solve() 函式中,
h[]
的合併順序可以看做是
\(2i\) 是左子樹,\(i\) 是當前,\(2i+1\) 是右子樹,則 h[i]=h[2*i]+h[i]+h[2*i+1]
表示 左-中-右,即中序遍歷
- 輸入 \(10\),輸出的第一行是
暴力模擬雜湊值即可透過本題
但是顯然有更好的解法,考慮到這個雜湊值在擴充套件的時候,每次都是乘 \(2^{l}\),再加上一個新的雜湊值,這是一個非常好的性質,假如我們把某一位的雜湊值看做一個 \(m\) 位的二進位制數,這樣的合併方式就會告訴我們,這個二進位制數對應的 \(l\) 一定等於 \(m\),因為初態時,對於 \(l=1\) 的節點,值恰好就是 \(1\),因此每次合併的時候,都會正好將左右兩邊的 \(h1\) 值拼接起來,形成一個新的二進位制數
因此我們可以直接利用這個性質,對 \(n=10\) 的完全二叉樹的中序遍歷 8 4 9 2 10 5 1 6 3 7
轉成二進位制數(該位編號是質數就為 \(1\),否則為 \(0\),詳見 H
的建構函式),即 \(0001010011_{d}=83\)
- 輸入
16
,輸出的第二行是
即問:\(n=16\) 時,子樹雜湊值不同的節點共有幾個(雜湊值不同在上方已有定義,即子樹結構或者子樹上節點的 p
陣列狀態存在不同)
可以發現 9 10 12 14 15 16
是相同的,11 13
是相同的,其餘都是不同的
因此為 \(16-(6-1)-(2-1)=10\) 個
完善程式
1
分析
upper_bound()
函式是有其固定作用的,含義為 “查詢有序序列中第一個大於給定元素的值的下標”,根據下面呼叫 upper_bound(b,b+n,...)
也可以發現,這裡的區間是左閉右開的
get_rank()
函式相當於二分答案裡的 check() 函式,這裡的作用是檢查當前和在所有 sum 裡的排名。這裡使用了一種寫法為 upper_bound(b,b+n,sum-a[i])-b
,假設我們固定 \(a_{i}\),那麼在 \(b\) 陣列裡,比 \(sum-a_{i}\) 小的元素值,與 \(a_{i}\) 的和也一定比 \(sum\) 小,因此我們就將它加到當前 \(sum\) 的排名前,這是這段函式的含義
solve()
即為二分答案函式,二分可能的 \(sum\) 值,找出排名恰好為 \(k\) 的那個
程式相對比較簡單,主要的難點可能在二分的格式上,如果你平常用的二分不是 l=mid+1,r=mid
格式,那麼可能就容易選錯
題目
-
選二分割槽間右端點,二分範圍是給定陣列,不少人會錯選
an-a-1
,然而因為是左閉右開的,因此應該選an-a
-
現在我們要找的是第一個大於 \(a_{i}\) 的數字,注意到
r=mid
應該說明兩點,首先說明當前點是合法的(否則應該直接調到 \(mid-1\)),其次說明當前值大了,合法說明嚴格大於查詢值,因此選a[mid] > ai
-
返回查詢元素的地址,這裡查到了第 \(l\) 個元素,因為地址從 \(a+0\) 開始,因此返回 \(a+l\)
-
仍然選二分割槽間右端點,由於二分的是 \(sum\) 的值,最大值應該是兩邊最大的元素相加,由於兩邊元素都單調不減,所以選最後兩個即可,注意最後的元素是 \([n-1]\) 不是 \([n]\)
-
同第二問,我們來分析,首先當前答案是不合法的,其次當前答案的排名應該較小,因此需要將 \(sum\) 的值變大,不合法說明不能取等,因此選
get_rank(mid) < k
2
分析
嚴格次短路演算法,即找出嚴格大於最短路的第二短路,首先來分析次短路演算法的邏輯:
- 跑最短路,分別記錄當前最短路與次短路
- 如果當前沒有任何路徑,那麼新找到的路徑成為最短路
- 如果新找到的路徑比當前最短路短,那麼新找到的成為最短路,之前的最短路成為次短路
- 如果新找到的路徑小於最短路但大於次短路,那麼新找到的路徑成為次短路
這樣,我們就能夠找到最短路和次短路
題目中要求輸出路徑,因此推測 pre
陣列是記錄路徑的陣列,dis
陣列按照一般最短路演算法,記錄的是節點到起點的最短路,這裡比較奇怪的是兩個指標 pre2
和 dis2
,它們是屬於次短路的陣列,你可以理解成它們也是獨立的陣列,只不過用的是 pre
和 dis
的空間
也就是說,dis[a]=(dis+n)[a-n]=dis2[a-n]
,dis2[a]=(dis+n)[a]=dis[a+n]
然後來看加邊,用的是鏈式前向星,加邊函式是 add
下面分析這個 upd
函式
寫過 dij 演算法的應該能看出來,這是一個鬆弛操作,因為其中有對 dis
的比較,賦值和優先佇列的 push()
,並且能看出來,鬆弛成功之後函式會返回 true,否則為 false,函式的引數中,a
是節點的前驅編號,b
是節點編號,d
是更新的距離,p
是一個優先佇列
在 solve() 函式里跑的就是一個比較正常的 dij
題目
- 這裡的目的是用當前最短路的
dis
去更新次短路的dis
,因為這兩個dis
分在兩個不同的陣列裡,所以可能會不相同,但只有兩個陣列相同才能進行鬆弛操作,所以需要統一一下,那麼這裡的前驅顯然是pre[b]
,節點編號應該是n+b
,因為我們要更新的是dis2[b]
,因為dis2=dis+n
,所以這裡應該為n+b
,距離是最短路距離dis[b]
- 考的是
pair<>
的關鍵字問題,pair<>
在排序的時候會優先以第一關鍵字排序,相同時以第二關鍵字排序,那麼這裡我們顯然應該優先排節點dis
而不是節點編號,所以應該是d
在前,然後應該是dis
小的在前,因為優先佇列把大的放在前面,所以為了實現小的在前面,我們應該插入一個負的,取出來的時候再把它變成正的就行了 - 不少人直接會無腦選
0x3f
,因為這個數好記,不會炸int
,並且夠大,但是這個題已經為我們定義了最大值const int inf
,所以我們直接照著inf
值選0x1f
- 這個地方是已經鬆弛過最短路了,並且失敗了,現在要來嘗試鬆弛次短路,和上面第二題一樣,次短路編號為
n+b
,因為我們還沒更新dis2
,所以這裡不能用dis2[a]+c
,只能用dis[a]+c
- 上面的判斷語句告訴我們現在
a
比n
大(並且一定比2n
小),所以我們直接調dis2[a]
會越界(但是在這裡呼叫dis[a]
就是可以的),為了不讓其越界,我們應該呼叫dis2[a-n]
,即dis2[a%n]