CF368B Sereja and Suffixes 題解
Content
有 \(n\) 個數 \(a_1,a_2,a_3,...,a_n\)。有 \(m\) 次詢問,每次給定一個數 \(l\),查詢在區間 \([l,n]\) 內不同的數一共有多少個。
資料範圍:\(1\leqslant n,m\leqslant 10^5,1\leqslant a_i\leqslant 10^5\)。
Solution
鑑於 \(\mathcal{O}(nm)\) 的暴力模擬顯然不能夠通過此題,我們需要一種更高效的演算法,以卡過這樣的資料。
那麼,我們自然而然就會想到 \(\texttt{dp}\) 的演算法了。
既然是要求 \([l,n]\) 裡面的不同的數的個數,那麼我們不妨就設 \(dp_i\)
很顯然,\([n,n]\) 裡面不同的數只有 \(a_n\) 一個,對吧?那麼我們就從這個臨界點開始從右往左進行 \(\texttt{dp}\)。
為了統計這個數字是否出現,我們需要開一個 \(vis\) 陣列(這裡 \(a_i\) 的值不算太大,如果很大的時候就需要用到 \(\texttt{map}\) 來實現了)。那麼,這個題目的轉化方程就很容易想到了:如果在 \(i\) 之後出現了一個數 \(j\),使得 \(a_j=a_i\),那麼 \(dp_i\) 就保持和 \(dp_{i+1}\)
這樣,轉移方程就列完了:
\[dp_i=\begin{cases}1&i=n\\dp_{i+1}+1&vis_{a_i}=0,1\leqslant i<n\\dp_{i+1}&vis_{a_i}=1,1\leqslant i<n\end{cases} \]我們拿樣例 \(1\) 做個例子:
1 2 3 4 1 2 3 4 100000 99999
顯然,\(dp_{10}=1\)。
更新 \(vis_{99999}=1\),從 \(10\) 這個位置開始從右往左掃。
-
掃到 \(9\) 這個位置,顯然,後面並沒有出現 \(100000\) 這個數,所以 \(dp_9=dp_{10}+1=2\),並更新 \(vis_{100000}=1\)。
-
掃到 \(8\) 這個位置,顯然,後面並沒有出現 \(4\) 這個數,所以 \(dp_8=dp_9+1=3\),並更新 \(vis_4=1\)。
-
掃到 \(7\) 這個位置,顯然,後面並沒有出現 \(3\) 這個數,所以 \(dp_7=dp_8+1=4\),並更新 \(vis_3=1\)。
-
掃到 \(6\) 這個位置,顯然,後面並沒有出現 \(2\) 這個數,所以 \(dp_6=dp_7+1=5\),並更新 \(vis_2=1\)。
-
掃到 \(5\) 這個位置,顯然,後面並沒有出現 \(1\) 這個數,所以 \(dp_5=dp_6+1=6\),並更新 \(vis_1=1\)。
-
掃到 \(4\) 這個位置,顯然,位置 \(8\) 出現了 \(4\) 這個數,有 \(vis_4=1\),所以 \(dp_4=dp_5=6\)。無須再更新 \(vis_4\) 了,下同。
-
掃到 \(3\) 這個位置,顯然,位置 \(7\) 出現了 \(3\) 這個數,有 \(vis_3=1\),所以 \(dp_3=dp_4=6\)。
-
掃到 \(2\) 這個位置,顯然,位置 \(6\) 出現了 \(2\) 這個數,有 \(vis_2=1\),所以 \(dp_2=dp_3=6\)。
-
掃到 \(1\) 這個位置,顯然,位置 \(5\) 出現了 \(1\) 這個數,有 \(vis_1=1\),所以 \(dp_1=dp_2=6\)。
這樣,所有的 \(dp\) 陣列全部更新完了:
\[\begin{cases}dp_1=6\\dp_2=6\\dp_3=6\\dp_4=6\\dp_5=6\\dp_6=5\\dp_7=4\\dp_8=3\\dp_9=2\\dp_{10}=1\end{cases} \]顯然,這和樣例所給出的答案完全相符。相信對這個 \(\texttt{dp}\) 的過程有了一定的加深理解。
那麼,既然\(\mathcal{O}(n)\) 的 \(\texttt{dp}\) 預處理完了,剩下的詢問就可以直接 \(\mathcal{O}(1)\) 輕鬆搞定了,這下就可以輕鬆通過此題了。
Code
本題只放 \(\texttt{dp}\) 過程的核心程式碼部分,其中:
- \(dp_i\) 表示 \([i,n]\) 內不同的數的個數。
- \(vis_i\) 表示 \(i\) 是否出現過,是的話 \(vis_i=1\),否則 \(vis_i=0\)。
f[n] = 1;
vis[a[n]] = 1;
for(int i = n - 1; i >= 1; --i) {
if(!vis[a[i]]) {
f[i] = f[i + 1] + 1;
vis[a[i]] = 1;
} else f[i] = f[i + 1];
}