P11231 [CSP-S 2024] 決鬥 題解

ZYStream發表於2024-11-02

這道題最初的思路是用數值大的打數值小的而且這一打不能使數值大的那個浪費,先對 \(r\) 陣列進行排序(規定從第 \(1\) 項開始)。

sort(r+1,r+1+n);

然後r陣列就成了一個不嚴謹的單調遞增序列,只需要將 \(r_{i}\) 攻擊\(r_{i-1}\)項就行,如果 \(r_{i}=r_{i-1}\) ,那麼 \(r_{i}和r_{i-1}\)兩個元素無法死亡。
考慮dp,我們用 \(\mathrm {f} _{i}\) 表示在排過序的 \(r\) 陣列中,從第一項到第 \(i\) 項時,最多會死掉多少個元素,易得到狀態轉移方程式為

\( f_{i}=\left \{ \begin{matrix} f_{i-1} & ,r_{i}=r_{f_{i-1}+1} \\ f_{i-1}+1& ,r_{i}>r_{f_{i-1}+1} \\ \end{matrix} \right. \)

那麼解釋一下這個方程式,\(f_{i}\)既然可以表示最多死亡個數,那麼死亡的元素一定是陣列中比較小的,截至到 \(r_{i}\) ,死亡的元素是 \(r[1,f_{i}]\) ,如果 \(r_{i}=r_{f_{i-1}+1}\) ,就說明兩個即將對戰的元素相等,那麼我們就知道這兩個元素誰都打不死誰,所以 \(f_{i}=f_{i-1}\) . 否則就說明 \(r_{i}\) 可以擊敗 \(r_{f_{i-1}+1}\),所以\(f_{i}=f_{i-1}+1\).
\(i\)\(1\) 時,答案一定是 \(1\),所以 \(i\)\(2\) 開始遍歷,最後輸出答案\(n-f_{n}\)即可。

憑藉這個思路,複雜度控制在了 \(O(n\log_{2}{n}+ n)\)
AC程式碼:

#include<cstdio>
#include<algorithm>
using namespace std;

int n;
int r[100005];
int dp[100005];

int main(){
    //freopen("duel.in","r",stdin);
    //freopen("duel.out","w",stdout);
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&r[i]);
    sort(r+1,r+n+1);
    for (int i=2;i<=n;i++) dp[i] = r[dp[i-1]+1]==r[i]?dp[i-1]:dp[i-1]+1;
    printf("%d",n-dp[n]);
    return 0;
}

相關文章