---
# System prepended metadata

title: 'TPOJ Round #5 Editorial'
tags: [Editorial]

---

# TPOJ Round #5 Editorial
###### tags: `Editorial`
## pA. Sleeping Patterns
根據題意，只需要檢查「$\ h2:m2$是否**不**介於 $\ h3:m3$ 和  $\ h4:m4$」及「$\ h4:m4$是否**不**介於 $\ h1:m1$ 和  $\ h2:m2$」即可。一個比較好的實作方式是將所有時間都換成分鐘數，這樣就可以使用整數判斷了。

## pB. Logarithm Game
應該不難想到以下的 Greedy 解：一直選擇加 $\ 1$ ，一旦遇到二個幂次就把它取對數。
幸運的是，這個解法就是對的！以下將證明這是最佳策略：
我們將所有除了 $\ 1$ 以外的正整數分成 $\ [2^0+1,2^1],[2^1+1,2^2], [2^2+1,2^3],[2^3+1,2^4]...$ 這些區塊。令 $\ b_k$ 代表區間$\ [2^{k}+1,2^{k+1}]$。我們對每個 $\ k$ 進行討論：
* 當 $\ k=0$ 時，$\ b_0$ 內只有一個整數 $\ 2$ 。顯然最佳的策略就是取 $\ log$ 一次。
* 討論當 $\ k=t$ 的情形。注意到我們的策略就是將 $\ b_{t}$ 內的所有數字加到 $\ 2^{t+1}$ 以後，然後取對數。注意到 $\ t+1 \leq \frac{2^{t+1}}{2}$，因此每個數字都只會被碰到一次，也就是操作次數不會超過 $\ 2^{t+1}$ 次。如果加到 $\ 2^{t+2},2^{t+3}...$ 再取 $\ log$ ，這樣的操作次數至少就是 $\ 2^{t+2}-2^{t+1} = 2^{t+1}$ 次，並不是最優策略。

Note: 延伸題目: 如果加 $\ 1$ 和取 $\ \log$ 不同權重? 

## pC. Edit Distance of Two Multisets

我們首先討論 $\ n=m$ 的情形。
令 $\ occx_i$ 代表 $\ S$ 中 $\ i$ 的出現次數， $\ occy_i$ 代表 $\ T$ 中 $\ i$ 的出現次數。我們計算以下兩個總和：
* $\ pos= \sum\limits_{occy_i>occx_i} occy_i-occx_i$
* $\ neg= \sum\limits_{occx_i>occy_i} occx_i-occy_i$

如果我們只能執行取代，那答案顯然是 $\ c \cdot pos$ (注意到在 $\ n=m$ 下 $\ pos=neg$ ) 。令 $f_1,f_2,f_3$ 分別代表最優策略下添加、刪除、取代的操作次數。注意到 $\ f_1 = f_2$ ，所以我們可以枚舉 $\ f_1$ 的執行次數，就可以用 $\ pos$ 算出 $\ f_3$ 的執行次數，那答案就是所有 $\ f_1 \cdot (a+b) + f_3 \cdot c$ 的最小值。但是注意到 $\ f_1$ 最佳解時一定是 $\ 0$ 或 $\ pos$ ，因此答案又可以寫成 $\ \min(a+b,c) \cdot pos$ 。

當 $\ n>m$ 時，顯然我們一定要執行至少 $\ n-m$ 次刪除操作， 然後就可以變成 $\ n=m$ 的情形了。當刪除時，我們可以永遠刪除 $\ occx_i>occy_i$ 數字 $\ i$，使得當 $\ n=m$ 時還需要 $\ neg$ 的花費，因此最少操作花費為 $\ b \cdot (n-m) + \min(a+b,c) \cdot neg$ 。我們可以類似的手法討論 $\ n<m$ 的情形。

結論：
* 當 $\ n=m$ 時，答案是 $\\min(a+b,c) \cdot pos$ .
* 當 $\ n>m$ 時，答案是 $\ b \cdot (n-m) +\min(a+b,c) \cdot neg$ .
* 當 $\ n<m$ 時，答案是 $\ a \cdot (m-n) + \min(a+b,c) \cdot pos$ .

Note: 延伸題目: 如果 $\ S,T$ 都可以修改? 

## pD. Tree Relabeling

首先先找出原本的樹的樹直徑。顯然，這棵樹的樹直徑一定也是編號後的樹直徑。接下來的問題就變成，給定兩個正整數 $\ n,k$ ，找出一個長度為 $\ k+1$ 的序列使得每個整數都介於 $\ 1$ 到 $\ n$ 之間且不重複，並且 $\ \sum\limits_{i=1}^k |a_i-a_{i+1}|$ 達到最大值。

$\ k$ 個絕對值的總和可以表示成 $k$ 個被減數的總和減去 $k$ 個減數的總和。其中每個整數最多被使用兩次。底下使用紅色的點代表被減數，綠色的點代表減數。我們將 $k$ 分奇偶討論。

1. $k$ 是奇數：

達到最大值時一定是這種情形(畫有點醜請見諒><)：
![](https://i.imgur.com/29ExIto.png)
我們也可以確實找到一種滿足這個最大值的編號方式：6 -> n-5 5 -> n-4 -> 3 -> ... -> 1 -> n 。

2. $k$ 是偶數：

達到最大值時是這種情形：
![](https://i.imgur.com/cq86aGG.png)
但是我們找不到一個滿足這個最大值的編號方式。於是我們退而求其次減 $1$ ：
![](https://i.imgur.com/IX2iWWg.png)
這個就有一種編號方式了： n-4 -> 5 -> n-3 -> 4 -> n-2 -> 3 -> ... -> 1 -> n-5 。

把在樹直徑上的編號確定後，剩下的編號隨意填就是了。

Note: 延伸題目: 如果把這題最大改成最小?(我其實也不會XD)

## pE. Palindromic Substrings

注意到在這個字串中，任意一個回文長度都是奇數。另外也注意到字串中最大的字母只出現一次。綜合以上我們枚舉回文的中心，嘗試使用以下 D&C 算法來計算回文數量：

* 令字串 $\ s_l ... s_r$ 中位置 $\ x$ 的字母是最大的，遞迴計算 $\ s_l ... s_{x-1}$ 及 $\ s_{x+1} ... s_{r}$ 的回文數量。
* 把上面的兩個值加起來，再加上 $\ \min(x-l+1,r-x+1)$ 就是答案了。

以上算法是正確的，但是時間複雜度是 $\ O(n)$ 。但是透過 DP 預處理長度為 $\ 1,2,4,8,...$ 的回文數量，就可以將複雜度降為 $\ O(\lg n)$ 。實作可以參考程式碼：

```
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const ll mod=1e9+7;
#define int ll

int dp[45],L,t,R;

int solve(int l,int r,int ql,int qr)
{
    if (r<ql||l>qr) return 0;
    else if (l>=ql&&r<=qr) return dp[__lg(r-l+2)-1];
    int m=(l+r)>>1;
    int ret=(m>=ql&&m<=qr ? min(qr-m+1,m-ql+1) : 0);
    return (ret+solve(l,m-1,ql,qr)+solve(m+1,r,ql,qr))%mod;
}

int32_t main()
{
    ios::sync_with_stdio(0); cin.tie(0);
    dp[0]=1;
    for (int i=1;i<=40;i++)
        dp[i]=(2*dp[i-1]+(1ll<<i))%mod;
    cin>>t;
    while (t--)
    {
        cin>>L>>R;
        cout<<solve(1,(1<<26)-1,L,R)<<'\n';
    }
}

```
Note 1: 這題是受到 CatAgain 出的題目啟發的: http://csdc.tw/contest/5/problem/13/
Note 2: 這題是這六題我最喜歡的題目 ><
Note 3: 延伸題目: 如果可以修改字串?

## pF. Cycle Queries

首先注意到，「$\ x,y$間有一個環穿過」相當於 $\ x,y$ 在同一團 BCC 中。所以現在問題變成怎麼維護一張圖中 BCC 的資訊。

注意到在一張圖中，BCC縮點後會成為一棵樹。而在 $\ x,y$ 間加邊就相當於縮點後將 $\ x,y$ 代表的點的路徑全部縮為一團 BCC 。於是解法就出現了：我們可以使用 DSU 維護每團BCC的資訊！詳細作法如下：

* 找出原圖的一顆生成樹。
* 每團 BCC 紀錄編號大小、最小的點、第二小的點、子樹頂端(因為每團BCC都是生成樹的一顆子樹)。
* 當加上一條邊 $\ (x,y)$ 後，把 $\ x$ 到 $\ lca(x,y)$ 和 $\ y$ 到 $\ lca(x,y)$ 合併為同一團。我們可以使用類似 LCA 的寫法：把 $x$ 和 $y$ 提到那團的頂端後，看兩者是否相同；如果不同，把比較低的那個跳一個節點上去。
* 當詢問時，如果該團大小為 $1$ 輸出 $-1$ ；如果詢問點為該團 DSU 最小的，輸出第二小的節點；否則輸出最小的節點。

Note1: 這題的解法可以拿來解CF的這題: https://codeforces.com/gym/100551/problem/B
(雖然那場是時間線段樹的Round就是了XD)
Note2: 延伸題目: 如果可以拔邊?