---
# System prepended metadata

title: NHSPC 決賽 2021~2022

---

# NHSPC 決賽 2021~2022
## 2022
[題目](https://nhspc2022.twpca.org/release/problems/problems.pdf)
### B. 自行車歸位 (bicycle)
有$n$個腳踏車，$m$個空位，給定一維座標，問把所有腳踏車都移到空位的最小總距離。
:::spoiler 解法:
從範例開始觀察，可以發現當$m=n$時，照順序由小到大依序歸還必是一組最佳解。也不難推出，對於所有情形，必有一組最佳解為 腳踏車座標越大，歸還座標越大。

為了簡化問題，我們將所有的$a<b<x<y$ $a\rightarrow x, b\rightarrow y$換為$a\rightarrow y, b\rightarrow x$，即所有的連線皆完全包含或不相交。
一輛腳踏車 b 只會有兩個可能被歸還的地方：
$l_b$:在$b$左邊，滿足$[l_b, b]$間腳踏車與空格數量相等，座標最大的空位
$r_b$:在$b$右邊，滿足$[b, r_b]$間腳踏車與空格數量相等，座標最小的空位
可利用stack在線性時間得出所有可能的連線，然後再做一次dp就好了。
:::
### C. 卡牌 (card)
每一回合從未選卡牌序列的最左邊或最右邊選一張卡片。隨著每回合減少了一張卡牌，剩餘卡牌的得分就會各加上其最初得分的十分之一，也就是第$k$回合結束時還未選的卡牌的得分
會為最初得分的$1+0.1k$倍。在最佳的選卡策略時，給定的卡牌序列最多可以獲得多少總得分？
保證初始分數皆為10的倍數。
* $n\leq 1000$
:::spoiler 解法:
定義dp[i][j]為，序列剩下[i,j]時，目前可獲得的最大分數，有可能從dp[i][j+1] or dp[i-1][j]轉移。
```cpp=
for(int i=0;i<n;i++){
		for(int j=n-1;j>=i;j--){
			if(i>0) dp[i][j]=max(dp[i][j],dp[i-1][j]+v[i-1]*(10+n-1-j+i-1)/10);
			if(j<n-1) dp[i][j]=max(dp[i][j],dp[i][j+1]+v[j+1]*(10+n-1-j-1+i)/10);
		}
	}
```
最後答案即為
```cpp=
for(int i=0;i<n;i++) ans=max(ans,dp[i][i]+v[i]*(10+n-1)/10);
```
:::
### D. 文字編輯器 (editor)
有以下規則:
• 單獨一個$x$是一個合法表達式。
• 如果$e$是合法表達式，則$|e|$也是合法表達式。例如:$x$是合法表達式，所以$|x|$也是合法表
達式。
• 如果$e$是合法表達式，則$[e]$也是合法表達式。例如：$x$是合法表達式，所以$[x]$也是合法表
達式。
• 如果$e1$和$e2$是合法表達式，則$e1+e2$也是合法表達式。例如：$|x|$和$[x]$是合法表達式，所以
$|x|+[x]$也是合法表達式。
現給一個只由"$x$"、"$|$"、"$+$"組成的字串，要把恰一個"$|$"改成"$+$"，並把剩下的"$|$"都改成"$[$"或"$]$"。
:::spoiler 解法:
先觀察到一件事:"$[$"和"$]$"必在"$x$"、"$+$"之間，連在一起的一定都同方向，"$x$"左邊必為左括號，右邊必為右括號。
先找$+$可能放的區間(必在兩個"$x$"之間)，窮舉放的位置，如果左邊的和($[$為1，$]$為-1)+右邊的和=$0$，就是合法的。
:::
### E. 齒輪組 (gears)
齒輪彼此接合或帶動，問最後一個齒輪的方向和轉速。
:::spoiler 解法:
直接線性做就好。
:::
### F. 百萬刮刮樂 (scratchcard)
有$n$張卡片，每張卡片$i$上面，由上至下依序有四筆數字$W_i, A_i, B_i, C_i$，其中$W_i\in \{ 1e6, 2e6, 3e6\}$。
抽出兩張相異卡片$x$和$y$，如果這兩張卡片上面的數字滿足以下條件，那麼中獎金額就是$K=W_x+W_y$，否則就沒有中獎。
條件:兩張卡片的$A, B, C$值相加皆須大於等於$K$
問有可能的$K$有多少種。
* $n\leq 2e5$
* $A_i, B_i, C_i\leq 6\times 10^6$
:::spoiler 解法:
$K$只有可能是$2e6, 3e6, 4e6, 5e6, 6e6$，所以題目變成:給定$K$，是否存在兩張刮刮樂滿足條件
若只有一個條件(如$A$)可以先排序後用簡單的用雙指標算對於每一個$i$，有那些$j>i$滿足$A_i+A_j\geq K$。
現在要再加入兩個條件，可以想成維護一個資料結構，檢查完$i$要檢查$i+1$時，把可以和$i$配但不能和$i+1$配的$j$拿掉。

---
現在的問題是:要如何建立一個資料結構可以查詢是否有$j$滿足$B_j\geq K-B_i$ 且$C_j\geq K-C_i$，並且可以支援刪除。
**對B的值域開線段樹**，存C的值，查詢[$K-B_i, B_{max}$]中
C的最大值是否大於等於$K-C_i$。
另外要注意因為$B$有可能重複，每個葉節點裡面要再放個multiset儲存該$B$值對應的$C$值。
:::
### G. 算樹 (tree)
給一棵樹的每個節點的度數，求可能的[Prüfer序列](https://zh.wikipedia.org/zh-tw/%E6%99%AE%E5%90%95%E5%BC%97%E5%BA%8F%E5%88%97)中，字典序第$k$小的。
:::spoiler 解法:
先觀察(或通靈)出一個性質:一個點在序列中出現的次數恰為 該點的度數$-1$ ，且任何序列都可以構造出一棵樹。
因此用排列組合算出一個序列的排列數，然後再依次算第一位、第二位該放哪個數字。往下一個位數做的時候不需要再重新算一次排列數，可以直接由上一個位數轉移。詳細如下:

定義數字$i$在序列中出現$a_i$次
所有的排列數為
$$
K := \frac{(a_1+n_2+\ldots+a_n)!}{a_1! a_2! \ldots a_n!}
$$
以$i$為開頭的序列個數為:
$$
K_i := \frac{(a_1+\ldots+a_n -1)!}{a_1! \ldots (a_i-1)! \ldots a_n!} = K\frac{a_i}{a_1+\ldots+a_n}
$$
:::
### I. 聖誕燈飾 (xmas)
有一組$n$顆$m$色燈泡的燈飾。這些燈泡排成一列，由左至右編號為$1, 2\cdots n$。燈泡的顏色是可變的，編號為$1, 2\cdots m$。若一顆燈泡的顏色為$i$，其中$i\leq m$，則改變顏色會變為$i+1$；若一顆燈泡的顏色為$m$，則改變顏色會變回$1$。
每顆燈泡下皆有一個按鈕可以改變燈飾整體的顏色，按下燈泡$k$的按鈕，會一齊改變燈泡$k, 2k, 3k\cdots$的顏色。例按下燈泡 2的按鈕，只能使編號為偶數的燈泡變色。已知初始 n 顆燈泡的顏色分別為$a_1, a_2\cdots a_n$，小千打算按下$\zeta _i$次燈泡$i$的按鈕，使得最後的顏色變成 $b_1, b_2 \cdots b_n$，請幫她找出滿足條件的$\zeta _1, \zeta _2\cdots \zeta _n$。若有多組滿足條件，請找出字典序最小的那組；若不存在這樣的方案，請輸出$−1$。
:::spoiler 解法:
先把問題轉換為以下數學式:
$$
\begin{cases}
\begin{aligned}
\zeta _1&\equiv b_1-a_1\\
\zeta _1+\zeta _2&\equiv b_2-a_2\\
\zeta _1+\zeta _3&\equiv b_3-a_3\\
\zeta _1+\zeta _2+\zeta _4&\equiv b_4-a_4\\
\vdots\\
\Sigma _{d|n} \zeta _d&\equiv b_n-a_n
\end{aligned}
\end{cases}
mod(m)
$$
題目要求字典序最小，因此$\zeta _1=b_1-a_1$，那麼$\zeta _2$就可以代入$\zeta _1$求出來，以此類推。
因此作法如下:
對於每個$i$，將第$2i, 3i\cdots$條算式都減掉$\zeta _i$，就能保證走到每一條算式時都只會剩下一項。
:::
## 2021
[題目](https://tioj.ck.tp.edu.tw/pmisc/nhspc110.pdf)
### [A. 髮廊服務優化問題(barbershop)](https://tioj.ck.tp.edu.tw/problems/2251)
給定$n$位客人需要的服務時間，問最小的總等待時間。
* $n\leq 200$
:::spoiler 解法:
排序後greedy地從最大的開始。
:::
### [B. 校園公車 (bus)](https://tioj.ck.tp.edu.tw/problems/2252)
有一條由$n$個線段組成的折線，給一個點$O$，問此點到折線的最短距離。
:::spoiler 解法:
窮舉每一條線段，最後取min。
先用畢氏定理判斷點$O$和線段兩端圍成的三角形是否為鈍角三角形。
若是，則最近的點為線段兩端點之一。
若非，用向量外積算出三角形面積，然後除以線段長度，即為點到線段最短距離。
[向量寫法](https://hackmd.io/@Viecon-342524/HJLBoymz2#%E5%90%91%E9%87%8F)
:::
### [D. 汽車不再繞圈圈(car)](https://tioj.ck.tp.edu.tw/problems/2254)
給一張有邊權的有向圖，管理員有權限值$P$可以將任意條邊權小於等於$P$的邊翻轉方向，使得圖中不存在環。問最小的$P$為何，並輸出一種翻轉方案。
:::spoiler 解法:
對排序後的邊權二分搜答案(因為$P$一定等於某一個邊權)，若要檢查$x$，可以先把所有邊權小於等於$x$的邊都刪掉，檢查剩下的圖是否有環，若剩下的圖沒有環，那麼加任意條可以改變方向的邊，一定有辦法構造出一種方案。就可以找出最小的$P$了。

找出$P$後，如何找出翻轉方案?
對剩下的圖做[拓撲排序](https://hackmd.io/@Viecon-342524/Hk-K-vw8j#%E6%8B%93%E6%92%B2%E6%8E%92%E5%BA%8F)，讓加入的邊符合這個順序。
因為加入符合順序的邊不會改變原本的拓樸順序，而只要所有點都在拓樸排序內，就一定不會有環。
:::
### [F. 挑水果 (fruit)](https://tioj.ck.tp.edu.tw/problems/2256)
有$c$種水果和$c$個城市，在第$i$個城市可以選擇是否要以每顆$S_i$元的價格將**前$i$種水果全部卸貨**，且對於種類$j$，能賣出$r_{i,j}$顆給消費者，另外到達第$i$城市時船上的每顆水果要花費$P_i$元(不論種類)，現給預算$T$，問在哪些城市卸貨能使賣出的水果最多。
:::spoiler 解法:
令`dp[i][j]`為最後一次在城市$i$卸貨，目前銷售量為$j$時所花的最小成本。
dp[這一次卸貨的地方][目前總共的銷售量]=dp[枚舉上一次卸貨的地方][上一次的銷售量]+船上的水果量$\times$這一段的總$P$+這個地方的$S$$\times$這一次的卸貨量


$$
dp[i][j]=\mathop{\min}_{0\leq k<i} (dp[k][j-\sum _{x=k+1} ^i r_{i,x}]+\sum _{x=k+1} ^c n_{x} \times \sum _{x=k+1} ^i P_x+S_i\times \sum _{x=k+1} ^i n_x)
$$

sigma 可以用前綴和處理。然後算答案時記得加上船上剩餘的水果載到終點的運費。
最後答案即為不超過$T$的答案中最大的$j$
:::
### [G. 鳳梨關稅 (pineapple)](https://tioj.ck.tp.edu.tw/problems/2257)
給一個樹，支援兩種操作:
1. 將一條邊的權重從$1$變為$0$
2. 問從根節點到某個節點的權重總和
:::spoiler 解法:
[樹壓平](https://hackmd.io/@Viecon-342524/r1qfzJEm3#%E6%A8%B9%E5%A3%93%E5%B9%B3)後就可以套BIT或線段樹了。
:::
### [I. 鐵路鋪設 (rail)](https://tioj.ck.tp.edu.tw/problems/2259)
有一個$2*L$的矩形，有多少種鋪鐵路的方式?
規則:
每個格子只有一條路線，路線皆須要是環，每條路線至多只有一條是斜的
![](https://hackmd.io/_uploads/Sk8vTSPrh.png)
:::spoiler 解法:
這題有滿多種想法的，這裡提供一種。
假設以$A_L$表示$L$的答案，且定義$A_0=1, A_1=0$。
有$A_{L-1}$種情況可從$L-1$往右延伸一格:
![](https://hackmd.io/_uploads/Hye-CIwHn.png)

---
那麼有哪些情況不能從$L-1$延伸?
最右邊為這三種情形:
![](https://hackmd.io/_uploads/HJJMlDvS2.png)

針對第三種情形，方法數就等同於$A_{L-2}$。
針對第一種，可以枚舉倒數第二個環的大小，以下以$L=5$為例。
![](https://hackmd.io/_uploads/BJ4yZvvBn.png)
![](https://hackmd.io/_uploads/rJei7-DDrh.png)
![](https://hackmd.io/_uploads/BkrvbwDrn.png)
可以觀察出有$A_{L-3}+A_{L-4}+\cdots +A_0$種
且第二種和第一種一樣多。
把上面全部加起來可以得到:
$$
\begin{aligned}
A_L&=A_{L-1}+A_{L-2}+2(A_{L-3}+A_{L-4}+\cdots +A_{0})\\
&=A_{L-1}+A_{L-3}+A_{L-2}+A_{L-3}+2(A_{L-4}+A_{L-5}+\cdots +A_0)\\
&=A_{L-1}+A_{L-3}+A_{L-1}\\
&=2A_{L-1}+A_{L-3}
\end{aligned}
$$
這個很漂亮的算式。
最後再套進[矩陣快速冪](https://hackmd.io/MGfghW7KQu2MdWTOzM6WcQ?view#%E7%9F%A9%E9%99%A3%E5%BF%AB%E9%80%9F%E5%86%AA)就好了
:::
## 參考
https://nhspc2022.twpca.org/editorial/editorial